#velocity
1 messages ยท Page 2 of 1
lgtm
It works quite well
I did not implement this method as adventure defines it like this:
Plays a sound at the location of the recipient of the sound.
Since we can't fulfill that, would it be fine to break that contract by replacing the javadoc?
I did not implement the Player#playSound(Sound) method as adventure defines it like this:
Plays a sound at the location of the recipient of the sound.
Since we can't fulfill that, would it be fine to break that contract by replacing the javadoc?
I'll be honest, I tried this pull request for 30 minutes without knowing why the sound wasn't playing, since stopSound was working for me, until I saw that the #playSound(Sound) method wasn't implemented
From a plugin developer's perspective, this method should be implemented, but from a contract compliance perspective, it's okay not to implement it as required by the contract. With this in mind, good documentation at https://docs.papermc.io/velocity/dev/pitfalls/#audience-operations-are-not-fully-supported would suffice, so I am now reverting my change
@Emilxyz we are waiting for you :)
What do you say about stuffing override dialog api methods into this pr as well for documentation purposes?
Hi, for anyone who cannot wait, there is a velocity fork known Velocity-CTD which has this feature. (and others)
we are waiting for you
I'm not a team member, just sharing my thoughts, so my approval is not actually required. Also a friendly reminder that everyone is doing this on their free time, so it's not really needed to bump a review request after only a day.
I gave this another look and it basically lgtm other than these minor things in review comments.
Another thought I had (but I would wait with doing any changes) is that maybe we can just use ServerInfo for this instead of adding a new type, they basically share the same fields and probably will continue to do so in the future as well.
Also there is the issue of the planned config api switch which is holding up other things already that would make changes to the config, so be prepared for this pr to also be affected by this
* Copyright (C) 2018-2025 Velocity Contributors
* Copyright (C) 2018-2025 Velocity Contributors
All remaining internal calls to this should be changed to the new #getBackendServers(). You can then remove this method and move its content into VelocityConfiguration#getServers, or maybe as a default in ProxyConfig#getServers itself even
This would throw a IllegalArgumentException, not illegal state
87f74ea [ci skip] Improve documentation for priority param... - Ecconia
37f622f feat: add ProxyPreShutdownEvent before players are... - DartCZ
ec793a9 Log console command executions (#1137) - Joo200
94368d5 Update publishing endpoint - 4drian3d
ba01492 Minecraft 1.21.9 (#1651) - RealBauHD
77933a8 Merge branch 'dev/3.0.0' into update/java/21 - 4drian3d
Should this work with RC1? I deployed velocity build 539 with Paper 1.21.9-RC1-30, and the client keeps saying Incompatible Client! Please use 1.7.2-1.21.9
Neither velocity nor MC show anything in the logs when I try to connect.
This will not work with rc1 as that uses the snapshot protocol and only the release protocol was added to the dev/3.0.0 branch
Should this work with RC1? I deployed velocity build 539 with Paper 1.21.9-RC1-30, and the client keeps saying Incompatible Client! Please use 1.7.2-1.21.9 Neither velocity nor MC show anything in the logs when I try to connect.
This pull request was merged to prepare support for Minecraft 1.21.9.
Since the release candidate has been published and a release date is approaching, we can be sure that there will be no changes that will break compatibility.
There are no plans to support snapshots in the main builds
IMHO this shouldn't exist, I think a better handling would be if a forwarding mode was not specified (e.g null), use the global one from config
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.
* within {@link PlayerClientLoadedWorldEvent#TIMEOUT} after the player joined the server.
return handler.handle(this);
also should be changed to 2 spaces indentation, applies to the entire class
I'm still encountering the same issue while using velocity-3.4.0-SNAPSHOT-514. From time to time, when players switch servers, the disconnect event doesn't get triggered properly on the original server.
Is there any solution to this problem?
Al parecer lo solucionaron en SNAPSHOT-#536 verificare su funcionamiento.
Not sure if you intended to have me re-review but I gave this a whirl on a test and production instance without issues on versions even below 1.20.2/3. Should be all set as far as Iโm concerned!
Scoreboard teams also need to be tracked, since those aren't cleared by the respawn packet (just like objectives).
(this is just a comment about the PR and should not be taken as a statement about whether we want this in velocity)
Expected Behavior
None
Actual Behavior
When I use a Chinese name and enter the /server command on the server for cross-server use, it prompts: Expected whitespace to end one argument, but found trailing data at position 7: server <--[HERE]
[servers]
"็ปๅฝๅคงๅ
" = "127.0.0.1:52020"
"ๅ็็ๅญ" = "127.0.0.1:52011"
"็ฉบๅฒ็ๅญ" = "127.0.0.1:52022"
"่ฃ่็บชๅ
" = "127.0.0.1:52033"
try = [
"็ปๅฝๅคงๅ
"
]
[forced-hosts]
"lobby.sakura18.cn" = [
"็ปๅฝๅคงๅ
"
]
"factions.sakura18.cn" = [
"ๅ็็ๅญ"
]
"skyisland.sakura18.cn" = [
"็ฉบๅฒ็ๅญ"
]
"mmorpg.sakura18.cn" = [
"่ฃ่็บชๅ
"
]
Steps to Reproduce
None
Plugin List
None
Velocity Version
velocity-3.4.0-SNAPSHOT-535
Additional Information
None
That's a vanilla problem
You are only allowed to use a-z A-Z 0-9 and some other symbols
This is a duplicate of https://github.com/PaperMC/Velocity/issues/1362 and https://github.com/PaperMC/Velocity/issues/1220.
Velocity could address this by making their server command use StringArgumentType#string() rather than StringArgumentType#word(), which is implemented in this PR: https://github.com/PaperMC/Velocity/pull/1363.
With the string type, non "standard" characters would have to be enclosed in quote ". As an alternative, Velocity could use StringArgumentType#greedy since the server argument is at the end of the command.
Note that you can for example not use greedy for the /send command and that would introduce inconsistency.
Note that you can for example not use greedy for the /send command and that would introduce inconsistency.
Really? It looks like the server argument of the send command is the last one?
<img width="658" height="82" alt="Image" src="https://github.com/user-attachments/assets/4e96d102-646b-4796-85bd-d167bac63a0a" />
Oh yea you're right.
(I think I remembered the bungee version)
When I try to connect to a server with 1.21.10 it says disconnected.
There were no protocol changes in 1.21.10
There were no protocol changes in 1.21.10
I figured it out it was an issue where I didnโt install FabricProxy-Lite on my Minecraft server with 1.21.10
When Velocity has not yet determined the player's ping, and the Velocity API is called, -1 is returned. This change allows that value to be set to any long value via velocity.toml.
What do you need that for?
If you want to use -1 for other things; or if you want to use a positive value. The client sees a negative ping as unable to connect
I'm migrating to Velocity and encountered the same issue.
I see no need to replace the default ping value
If you want to use -1 for other things
If you are making a plugin that obtains the player's ping, it should be in your plugin where you have the logic for displaying the ping
The only reason I can see for actually changing this would be to modify the ping value that other plugins can obtain, such as placeholder or statistics plugins... Why would you want to do that?
Updates adventure to version 4.25.0
See: https://github.com/KyoriPowered/adventure/releases/tag/v4.25.0
Expected Behavior
Here is my (paper) brigadier command.
public LiteralCommandNode<CommandSource> create() {
return literalArgumentBuilder("vtest")
.then(requiredArgumentBuilder("message", StringArgumentType.greedyString())
.suggests((ctx, builder) -> {
String input = builder.getRemaining().toLowerCase();
int location = -1;
for (int i = 0; i < input.length(); i++) {
if (input.charAt(i) == ':') {
location = i;
}
}
return builder.createOffset(location + builder.getStart() + 1)
.suggest("This suggestion should move behind semicolons")
.buildFuture();
})
.executes(ctx -> 1)
)
.build();
}
it does the following:
h...
On another note. I think it could be a good idea to remove the timeout mechanism entirely, as plugins could create a similar mechanism by e.g. scheduling in the ServerPostConnectEvent and storing whether the loaded event triggered.
Expected Behavior
Reported by a user on the PaperMC discord [here](#velocity-dev message)
"Velocity commit (806b386) seems to have changed command suggestions. Tab completing a suggestion replaced the previous argument however. Is this an implementation bug that shifted towards plugins to adjust for this offset, or is this unexpected behaviour?"
https://github.com/user-attachments/assets/293a041f-9ee3-4843-bbce-7778bada1385
Actual Behavior
Steps to Reproduce
Plugin List
Velocity Version
Additional Information
Since 1.21.5 URIs without a http:// or https:// in a open_url click event are no longer silently ignored but fail parsing and disconnect. Paper mitigates this in their codec by prepending a https:// to URIs with no protocol.
This PR enables JSONOptions.EMIT_CLICK_URL_HTTPS on our component serializers, to match papers behavior. To "fix" the disconnect the option would technically only be needed for >= 1.21.5, but I think it is best to just enable it for every version to stay consistent.
Related #1630
Expected Behavior
I want to be able to share libraries between my Velocity plugins. My current plugin setup is similar to this:
dependenciesec - contains Configurate
kingdoms - contains FileUtils, which loads configs with Configurate
gooeylibs - contains config base classes
eutils - contains config main classes
There are all velocity plugins.
Actual Behavior
I get this error whenever Configurate tries to load the class:
Unknown class of object ca.landonjw.gooeylibs2.api.configurable.button.BaseConfigButton
Steps to Reproduce
On proxy load, eutils calls FileUtils to load its configs. Configurate, then, calls Class.forName to load some gooeylibs class, but fails to do that.
This seems to be caused by Configurate calling Class.forName() and failing. I suspect there's some issues regarding classloading/PluginClassLoader preventing the classes from being found by Configurate, since I can do Class.forName from the other plugins and it works.
Plugin List
Plugins: v...
Why are you including Configurate in your plugin? Velocity provides Configurate 3 and Configurate 4
Besides that, it seems to be a Configurate issue rather than a Velocity issue
Why are you including Configurate in your plugin? Velocity provides Configurate 3 and Configurate 4
Besides that, it seems to be a Configurate issue rather than a Velocity issue
Good to know, thanks! Altrough even without shading Configurate it still throws the same error.
Velocity (and the libraries inside of it) cannot access the plugin classloaders, I'd imagine that if you shaded configurate without relocating it you'd end up with it using the velocity provided one; Configures object mapper would ideally provide a mechanism for overriding the classloader used here, not sure there is much we can do here
Is there any way I could make my (other) plugin classes accessible to Configurate/Velocity? Or allow my plugin classes to be discoverable by Configurate/Velocity somehow...
Expected Behavior
That the command to be passed through
Actual Behavior
The player is kicked due to an outdated check in Velocity's unsigned command packet
Steps to Reproduce
- setup a paper 1.21.10 server behind velocity
- be op on that server
- run
/fetchprofile name Timongcraft - click on "give item" or "summon mannequin" (and run command in the dialog)
Plugin List
none
Velocity Version
Velocity 3.4.0-SNAPSHOT (git-4cd3b686-b546)
Additional Information
I can confirm this, the vanilla limit is 32767. Ich wunder mich, wo die 256 รผberhaupt her kommen, ob es eine tatsรคchliche Limitation des Packets war oder nur wegen der Chatlรคnge genutzt wurde.
Afaik it was because of chat length, yea
Duplicate of #1629, there's already a fix for this but it just has to be merged still.
70c3eab Minor optimizations for MinecraftCompressorAndLeng... - astei
38a0a7e use correct string length for newer MC versions (F... - electronicboy
[PaperMC/Velocity] branch deleted: cat/increase-chat-string-limit
That update isn't relevant to Velocity, because we don't use BouncyCastle.
Netty 4.2.7 does contain changes relevant to us, so I updated with 13a1c93ea6e4816f489b6dbdf7b2cb94e64f6b2c.
[PaperMC/Velocity] New branch created: fix/reconfiguration-disconnect
eb5de18 Fixed disconnecting players in the middle of a bac... - 4drian3d
This seems to be a problem caused by ViaVersion, because if you try to connect with the same client and server version, there would be no problem. Also, protocol hacks plugins/mods are not usually supported
Expected Behavior
If I delete the
forwarding.secret file, Velocity should restore it and generate a new key.
Actual Behavior
After deleting the file, Velocity simply crashes with an error.
[14:33:26 ERROR]: Unable to read/load/save your velocity.toml. The server will shut down.
java.lang.RuntimeException: The forwarding-secret-file does not exist.
at com.velocitypowered.proxy.config.VelocityConfiguration.read(VelocityConfiguration.java:531) ~[velocity-3.4.0-SNAPSHOT-551.jar:3.4.0-SNAPSHOT (git-67b988e6-b551)]
at com.velocitypowered.proxy.VelocityServer.doStartupConfigLoad(VelocityServer.java:405) ~[velocity-3.4.0-SNAPSHOT-551.jar:3.4.0-SNAPSHOT (git-67b988e6-b551)]
at com.velocitypowered.proxy.VelocityServer.start(VelocityServer.java:293) ~[velocity-3.4.0-SNAPSHOT-551.jar:3.4.0-SNAPSHOT (git-67b988e6-b551)]
at com.velocitypowered.proxy.Velocity.main(Velocity.java:71) ~[velocity-3.4.0-SNAPSHOT-551.jar:3.4.0-SNAPSHOT (git-67b988e6-b551)]
###...
02cf349 Fixed disconnecting players in the middle of a bac... - 4drian3d
[PaperMC/Velocity] branch deleted: fix/reconfiguration-disconnect
[PaperMC/Velocity] New branch created: fix/generate-deleted-forwarding-file
4157882 Generate a new forwarding secret file if the file... - 4drian3d
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
b1dd26f 1.21.10 (#1658) - RealBauHD
d266059 Update adventure to version 4.25.0 (#1660) - cedricmkl
806b386 Fix command suggestion offset (#1662) - Rossterd
5753548 Fix SimpleCommand suggestion offset (#1664) - Rossterd
1140fc6 fix: Enable EMIT_CLICK_URL_HTTPS on component serial... - Emilxyz
4cd3b68 Fix players disconnecting when updating boss bars... - okx-code
70c3eab Minor optimizations for MinecraftCompressorAndLeng... - astei
38a0a7e use correct string length for newer MC versions (F... - electronicboy
13a1c93 Bump Netty to 4.2.7.Final - astei
498a38c Re-enable adaptive allocator - astei...
This is a really large PR, so review carefully.
This PR refactors Velocity's internal networking to use immutable(-ish) packets and splits encoding/decoding into separate codecs. This refactor isn't fully complete but there's enough to start doing more work on this.
I feel like this became unused from an earlier version of the change bellow
Why some classes like this one aren't records? It has public constructor, all final fields and record style getters, so I can't think of a reason
Why keeping both getter types is necessary?
I don't think it's worth converting every class to a record, it just wastes time. This feels like a very unimportant nit.
Because the AI (Claude) wanted to make sure the code compiled and it sometimes chose to amend the existing code and sometimes add in getters. I didn't steer it in that direction.
Again, while it's redundant, it's a nit that someone else can fix.
(Current maintainer of Proxy Compatible Forge)
I've just done a boatload of testing on Forge/NeoForge versions ranging from 1.14-1.21.10 and haven't run into this once.
(Current maintainer of Proxy Compatible Forge) I've just done a boatload of testing on Forge/NeoForge versions ranging from 1.14-1.21.10 and haven't run into this once.
My test setup is currently on Velocity 3.4.0-SNAPSHOT-540
The report was obviously made with another velocity versionโฆ.
It was fixed in build 474, which came out before your first comment.
Thought I'd mention that it's all working as expected nowadays, in case anyone comes across this issue when diagnosing errors.
[PaperMC/Velocity] New branch created: fix/null-ping-passthrough-description
afae4c6 Fixed sending ServerData packets if the descriptio... - 4drian3d
This appears to be a clear configuration error that can be resolved on our support server rather than here https://discord.gg/papermc
This appears to be a clear configuration error that can be resolved on our support server rather than here: https://discord.gg/papermc
It also seems that you have logged in with an โinvalidโ profile or probably without an official Minecraft account (which is not supported) and you have the enforce-secure-profile option enabled on your backend server
Expected Behavior
Some players are getting this error when trying to join the network.
Actual Behavior
Some players are getting this error when trying to join the network.
Steps to Reproduce
Some players are getting this error when trying to join the network.
Plugin List
Velocity: velocity, luckperms, maintenance, advancedserverlist, botsentry, librelogin, mckotlin-velocity, packetevents, pl-hide-pro, skinsrestorer, vlobby
Backend1: no plugins
Backend2 (15):
Paper Plugins (2):
- FancyHolograms, FancyNpcs
Bukkit Plugins (13): - BetterGUI, ChatManager, DeluxeHub, LuckPerms, Multiverse-Core, packetevents, Pl-Hide-Pro, PlaceholderAPI, SkinsRestorer, TAB, ViaBackwards, ViaVersion, VoidGen
Velocity Version
Velocity 3.4.0-SNAPSHOT (git-02cf3490-b552)
Additional Information
unable to connect to server auth
java.io.IOException: Unexpectedly disconnected from remote server
at com.velocitypowered.proxy.connection.backend.TransitionSessionHandler....
7412aca Fixed sending ServerData packets if the descriptio... - 4drian3d
[PaperMC/Velocity] branch deleted: fix/null-ping-passthrough-description
I was having a rough time narrowing down a mod that added some custom args under the minecraft: namespace, and found that the exception being thrown was always printing "null" and didn't provide any context as to what arg was causing the problem.
While poking around I noticed that 1.19.1+ had its exception in the right spot, so I've moved the other related exception from ArgumentPropertyRegistry#deserialize to ArgumentPropertyRegistry#readIdentifier.
f75b512 Moved pre-1.19.1 command argument validation so it... - p0t4t0sandwich
Sorry for the delay, I've checked it now.
It still doesn't work in the latest version (with the merge included).
This code fragment in TransitionSessionHandler fixes the issue:
<img width="1662" height="497" alt="image" src="https://github.com/user-attachments/assets/0598c104-1879-415a-85e4-91e646c470d6" />
Sorry for the delay, I've checked it now. It still doesn't work in the latest version (with the merge included).
This code fragment in TransitionSessionHandler fixes the issue: <img alt="image" width="1662" height="497" src="https://private-user-images.githubusercontent.com/28271340/503882613-0598c104-1879-415a-85e4-91e646c470d6.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NjEwODE3MzUsIm5iZiI6MTc2MTA4MTQzNSwicGF0aCI6Ii8yODI3MTM0MC81MDM4ODI2MTMtMDU5OGMxMDQtMTg3OS00MTVhLTg1ZTQtOTFlNjQ2YzQ3MGQ2LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTEwMjElMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUxMDIxVDIxMTcxNVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTFmOTc2YjQ4MWFhZTY0NWNhM2RiYTBhMTI2Mjc0OTg2MGQ3NTI2MmUzOTRmNzcwNTYyZmZlNGUxYjNlMTAxNWEmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.UxCzqxWeu3BAwoGU1Gp0fe6yyNealMH...
I would probably print something at the very least, just for the sake of debugging certain types of setups
b6b6b20 Generate a new forwarding secret file if the file... - 4drian3d
[PaperMC/Velocity] branch deleted: fix/generate-deleted-forwarding-file
Expected Behavior
In Velocity 3.4.0-SNAPSHOT (git-f75b5128-b554), the ProxyPingEvent occasionally provides
an InboundConnection where getRemoteAddress() returns null.
This causes NullPointerExceptions in plugins that expect a non-null remote address, such as AdvancedServerList.
Example error:
java.lang.NullPointerException: Cannot invoke "java.net.InetSocketAddress.getHostString()" because the return value of "InboundConnection.getRemoteAddress()" is null
Stacktrace:
at ch.andre601.advancedserverlist.velocity.listeners.VelocityEventWrapper.playerIP(VelocityEventWrapper.java:175)
at ch.andre601.advancedserverlist.core.events.PingEventHandler.handleEvent(PingEventHandler.java:63)
...
Steps to reproduce:
- Run Velocity 3.4.0-SNAPSHOT (git-f75b5128-b554)
- Install AdvancedServerList (or any plugin using ProxyPingEvent)
- Observe console when server list pings occur
Expected behavior:
getRemoteAddress() should never return null, or the API should document that this is pos...
Could you send a more complete log of the error?
You are only sending the stacktrace of the plugin, not Velocity.
This may be caused by plugins you have installed that provide their own InboundConnection, such as Geyser or LANBroadcaster.
I don't think LANBroadcaster is the cause, but I'll release an update to make sure
But still, it would be quite useful if you could provide the complete error message
Requested Feature
we should be able to add a code of conduct to velocity
Why is this needed?
for server owners
Alternative Solutions
using packets?
Additional Information
No response
I'm not really sure how viable it is to expose this given how weird configuration stuff is on the proxy without the backend server supporting this, resource packs are very weird as-is
Expected Behavior
I'm getting this error when entering certain locations on my modded server.(lobby: farbic 1.21.1)
Actual Behavior
Velocity error:
[23:47:00 INFO]: [connected player] HuanMoLu (/221.200.159.10:60304) has connected
[23:47:00 INFO]: [server connection] HuanMoLu -> lobby has connected
[23:47:02 ERROR]: [server connection] HuanMoLu -> lobby: exception encountered in com.velocitypowered.proxy.connection.backend.BackendPlaySessionHandler@18bd7153
com.velocitypowered.proxy.util.except.QuietRuntimeException: A packet did not decode successfully (invalid data). For more information, launch Velocity with -Dvelocity.packet-decode-logging=true to see more.
lobby server error:
[23:47:02] [Server thread/INFO]: HuanMoLu[/221.200.159.10:56361] logged in with entity id 390 at (100001.22851206471, 80.0, -49999.76083794844)
[23:47:02] [Server thread/INFO]: [Essential Commands] Loading PlayerData for player with uuid '7f465ae6-0c31-33f3-b50d-053ffc618d8a'.
[23:47:02] [Serve...
Update Velocity, you are using a very old version that is no longer supported
_However, the error could probably be fixed by installing Crossstich https://modrinth.com/mod/crossstitch_
Thank you! I update to velocity-3.4.0-SNAPSHOT-555 and install Crossitch, the problem has solved
Thank you. I update to velocity-3.4.0-SNAPSHOT-555 and install Crossitch, the problem has solved.
Worked fine in b540, and works fine for me in b555, so you'd most likely be running into an unrelated issue caused by some mod on the client.
Requested Feature
Add a function that could mask the IP of the internal server in logs and in the terminal.
Why is this needed?
The big problem is that players can be playing on different versions, whether 1.8 or 1.21.10, and you can't always use modern forwarding (as opposed to legacy/bungeeguard) to expand the list of available versions.
However, when a player fails to successfully connect to a server, the logs may show an error that shows the internal server's IP address. This isn't always safe, especially if you want to share plugin error logs or other information with others.
Alternative Solutions
Remove the IP address from the error yourself.
Additional Information
I don't think this should be the case. If there's a feature that allows you to hide players' IPs, why can't you hide servers' IPs? For example, I couldn't connect to a server and exposed my server's IP. If I provide the logs, I'll see.
[20:17:31 INFO]: [connected player] Asriel_NEO (/127.0.0.1...
That exception is not created under the control of velocity, and so we cannot directly obfuscate that information. I would generally suggest looking into using a log filter, this is not something I want to deal with, there are already log services out there that can obfuscate this information for you, such as https://mclo.gs
What if the IP is not digital but alphabetic?
You would need to look into log filtering/substitution, this is a nightmare of an issue that I do not think is worth the continual engineering effort
yeah, but when you instantiate a ServerInfo object what server forwarding mode do you'll pass there? null? I prefer keeping the FOLLOWUP mode and also the implicit mode (not writing explicitly in the config the forwarding mode of one or more servers) which already takes the default forwarding mode.
@MarcoLvr if a specific mode is not required make it null, then you will have something like:
// to determine app forwarding
ServerInfoForwardingMode mode = config.getServerInfoForwardingMode();
if (server.getServerInfoForwardingMode() != null)
mode = server.getServerInfoForwardingMode()
Starting from the last commit, in #getCurrentServer, the server will always be available
Should also mention here what passing null means, same as in BackendServerConfig like [...], or {@code null} if the mode from the config should be used (or something like that)
I think this should mention something about what it means if it's null
This (as well as the getter/constructor) should be marked as @Nullable
The field can also be final if you assign it to null in the other constructor
This jd also needs updating
This change increases the TabComplete limit in order to fix the now broken pasting of larger commands into command blocks after Mojang's change to the way Tab Complete works. It has been increased to 32767 from 2048, and this increase has no negative impact on performance, stability, or protocol compliance.
Mojang clients and servers already allow command strings up to 32767 characters, and this update brings Velocity in line with the vanilla protocol. This prevents unnecessary disconnections when pasting valid command block contents while retaining full protection against malformed packets.
No open issue for this bug. This is the error being observed: PasteBin velocity logs
This event allows modification of the server brand that is relayed to the player via the api.
This fixes a race-condition that affects Pterodactyl and similar panel hosted servers. It does not affect on Linux servers. This makes sure the configuration is explicitly created before doing any migrations or default setting.
This issue seems to have been tormeting newcomers for a while.
I fixed inline import and changed with proper import above
Removal of attribution is not something we desire to support
We and paper intentionally limited this in the past in order to restrict ongoing DoS attacks, I do ponder if it makes any sense to move this restriction elsewhere, I guess some limited adventage with brig is that it might be able to deal with this stuff a bit smarter than the older bukkit command system so maybe this wasn't too much of a problem for us, outside of network buffers
I don't think this actually fixes the issue since we are already do this using our config library: https://github.com/PaperMC/Velocity/blob/b6b6b20fe97cd9cb0d6b4e817d3e7db72aca2d8d/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java#L495
The "real" issue is that the docker images used by those panels include those "broken" minimal configuration files and our config library lacks the functionality to populate missing fields. I think a switch to a different config library is planned in the future
I don't think this actually fixes the issue since we are already do this using our config library:
To my understanding the "real" issue is that the docker images used by those panels include those "broken" minimal configuration files and our config library lacks the functionality to populate missing fields. I think a switch to a different config library is planned in the future
I worked with this fix with a person having the same issue, he said doing a explicit copy fixes it. He made a different patch for a different project but it worked. Today he is available again and I will ask him to test again. I will confirm soon.
Hey! Good news. This patch seems to completely patch the issue. I tested on a pterodactyl panel and now the file properly generates after applying this exact patch. You can safely merge. Thank you very much.
Hey! Good news. This patch seems to completely patch the issue. I tested on a pterodactyl panel and now the file properly generates after applying this exact patch. You can safely merge. Thank you very much.
nightconfig automatically generates a new configuration file if one doesn't exist. I've personally never had any issues regarding this.
Are there any examples of when nightconfig's file creation might fail? Are there any open issues related to this PR?
The nature of the PR comment around aspects like a race condition make 0 sense here, the config file either exists or it doesn't unless there is some janky issue elsewhere, in which, I would rather deal with a solution for that rather than manually copying the configuration file to the disk to work around something which now sounds even more questionable than before.
Either way, given past interactions with this author, I do not feel comfortable merging code submitted by them into this repo due to the legal risks it could potentially entail.
This PR resolves issue #1637 by adding Javadocs to CommandExecuteEvent and PostCommandInvocationEvent.
As said in #1635, developers are not always aware that Velocity does command rate limiting. This can lead to confusion when not all rapidly executed commands (usually done with macros or mods) trigger the corresponding events, as they are forwarded directly to the backend server.
These small changes clarify the intended behavior directly within the event documentation, preventing further confusion.
Also amidst controversy around me, some people seem to be randomly banning me or targetting me with weird claims about my persona, I just want to get along with everybody and just make great software together. I might be a little stupid sometimes, but it's my first time working with other people and I really want to learn finally being in community with fellow developers and make friends ๐
Still causing random OOM's.
[07:14:00 ERROR] [geyser]: Cannot reserve 8388608 bytes of direct buffer memory (allocated: 1067202503, limit: 1073741824)
[07:14:00 WARN] [geyser]: Downstream packet error! VarInt wider than 5 bytes
[07:14:00 WARN] [geyser]: Downstream packet error! Invalid packet id: 144867848
[07:14:00 WARN] [geyser]: Downstream packet error! readerIndex(36) + length(8) exceeds writerIndex(40): AdaptivePoolingAllocator$AdaptiveByteBuf(ridx: 36, widx: 40, cap: 40)
[07:14:00 WARN] [geyser]: Downstream packet error! (ClientboundContainerClosePacket) Packet "ClientboundContainerClosePacket" not fully read.
[07:14:00 WARN] [geyser]: Downstream packet error!
[07:14:00 WARN] [geyser]: Downstream packet error! Collection is empty
dcfd258 Evil attempt at ensuring we coax logger to flush - electronicboy
[PaperMC/Velocity] New branch created: shane/velocity-log-hack
It is strange that there is PlayerChannelRegisterEvent but no PlayerChannelUnregisterEvent, so I added it.
Is this feature planned or no? I want a global playerlist for my network but also want prefix's and player sorting. It doesn't seem to work without me putting TAB on each induvidial server, sacrificing the global player list.
Well in modern versions you can directly set the order, see: https://jd.papermc.io/velocity/3.4.0/com/velocitypowered/api/proxy/player/TabListEntry.html#setListOrder(int)
and setting the tab name has long been possible, see: https://jd.papermc.io/velocity/3.4.0/com/velocitypowered/api/proxy/player/TabListEntry.html#setDisplayName(net.kyori.adventure.text.Component)
Well in modern versions you can directly set the order, see: https://jd.papermc.io/velocity/3.4.0/com/velocitypowered/api/proxy/player/TabListEntry.html#setListOrder(int)
and setting the tab name has long been possible, see: https://jd.papermc.io/velocity/3.4.0/com/velocitypowered/api/proxy/player/TabListEntry.html#setDisplayName(net.kyori.adventure.text.Component)
So why doesn't TAB show the prefixes or sort players based on their permission group?
How would I know? You'd need to ask them
[PaperMC/Velocity] Pull request opened: #1687 Fix exception message formatting in command invocation
Before: java.lang.RuntimeException: Unable to invoke command examplecmd exampleargfor [connected player] SzymON_OFF (/1.1.1.1/11111)
After: java.lang.RuntimeException: Unable to invoke command examplecmd examplearg for [connected player] SzymON_OFF (/1.1.1.1:11111)
a046f70 Fix exception message formatting in command invoca... - szymon-off
So why doesn't TAB show the prefixes or sort players based on their permission group?
Because Scoreboard API hasn't been implemented in velocity, yet. I've just accepted that sorting by perm groups won't be a thing. Prefixes, however, works on my server network.
Because Scoreboard API hasn't been implemented in velocity, yet. I've just accepted that sorting by perm groups won't be a thing. Prefixes, however, works on my server network.
Velocity doesn't need a Scoreboard API for that to work though. It has no concept of 'permission groups' or any sort of grouping for that matter. So you would have to depend or a 3rd party to provide that or do it yourself, but a full-blown Scoreboard API is not needed for tablist sorting and formatting.
Seems like our server started to run into this too. Every once in a while velocity has a read timeout. We tried changing the network_compression_threshold to 64 and 128. We also attempted to change the connection-timeout value. Nothing seemed to fix it. Would be great if anyone has found a solution for this error. (We also tried it with no plugins at all besides Velocity and it was still occurring)
So why doesn't TAB show the prefixes or sort players based on their permission group?
Because Scoreboard API hasn't been implemented in velocity, yet. I've just accepted that sorting by perm groups won't be a thing. Prefixes, however, works on my server network.
I have a plugin installed on my proxy that adds support for scoreboards. Player prefixes and sorting shouldn't need the scoreboard API.
Player prefixes are 100% controlled by the scoreboard, not tab, and would require support for scoreboards; sorting is already implemented for the newer sorting mechanism in the display order field in the tab, anything else sorting wise relies on scoreboard team name sorting (backed by name sorting)
Seems like our server started to run into this too. Every once in a while velocity has a read timeout. We tried changing the network_compression_threshold to 64 and 128. We also attempted to change the connection-timeout value. Nothing seemed to fix it. Would be great if anyone has found a solution for this error. (We also tried it with no plugins at all besides Velocity and it was still occurring)
What Java GC engine you use?
Seems like our server started to run into this too. Every once in a while velocity has a read timeout. We tried changing the network_compression_threshold to 64 and 128. We also attempted to change the connection-timeout value. Nothing seemed to fix it. Would be great if anyone has found a solution for this error. (We also tried it with no plugins at all besides Velocity and it was still occurring)
What Java GC engine you use?
We're currently using G1GC
Since the ServerConnectedEvent doesn't seem to support sending plugin messages to the newly connected server, it would be helpful to be able to access the new server in ServerPostConnectEvent, where plugin messaging works.
Sorry for the weird formatting changes, I couldn't get my formatter to stop indenting the constructor arguments... the checkstyle seems to pass though...
The "new" server is already available in Player#getCurrentServer() when this event is fired, so I don't think we to need add it to this event
@bolda500 @KhrysAK47 by any chance are either of you using Proxy protocol v2?
Expected Behavior
i try to join and it not works
Actual Behavior
i tried everything and i made everything with a yt tutorial and its not working i also tried to make everything offline and no secuiยดrity but it still not workd annd i need a fast fix then my minecraft server network ist down becaouse of this
Steps to Reproduce
i dont know
Plugin List
noone
Velocity Version
newest snapschot
Additional Information
please fix
It seems to be an issue with how you have configured Velocity. You can get help on Discord
Requested Feature
I'd like to see the behavior of DisconnectEvent slightly changed for a more user-friendly (and less surprising) API.
Currently, DisconnectEvent is called when any player connection is closed for any reason at any point in the connection's lifecycle, this includes disconnects triggered by the user early in the login process, disconnects caused by the player already being on the server (with the kick option turned off), and disconnects caused by the pre-login events being cancelled. In all three of these cases, I think it's pointless to fire a DisconnectEvent when the corresponding LoginEvent has not been fired.
Furthermore, it'ss not immediately apparent (and not documented at all, actually) that DisconnectEvent covers so many cases, which means code like this is very common:
@Subscribe
public void onLogin(LoginEvent event) {
// e.g. create player data and add it to a UUID -> Data map
initialize(event.getPlayer().getUniqueId());
}
@Subscribe
public```...
i think a fork called velocity-ctd has that
Currently if you have the following command
var command = new BrigadierCommand(
literalArgumentBuilder("vtestcommand")
.then(literalArgumentBuilder("child")
.then(literalArgumentBuilder("grandchild")
.executes(ctx -> {
ctx.getSource().sendMessage(text("grandchild response"));
return 1;
})
)
)
);
/root and /root child get forwarded to the backend and handled there, but /root nonexistant gets handled on the proxy. This is because the former cause "UnknownCommand" exception, and the later causes an "UnknownArgument" exception.
The first commit in this PR aligns that behaviour, however this causes breakages in Simple/Raw commands as those assume they get handled on the proxy even if the user doesn't have the requisite permission. Which isn't true...
Changed โhuman readableโ to the grammatically correct compound adjective โhuman-readableโ in the plugin annotation to improve clarity and consistency across the documentation.
Expected Behavior
1.21.10 version:
io.netty.handler.codec.DecoderException: java.io.IOException: Packet play/clientbound/minecraft:set_border_warning_distance (afy) was larger than I expected, found 11 bytes extra whilst reading packet clientbound/minecraft:set_border_warning_distance
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:500)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:290)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
at io.netty.handler.flow.FlowControlHandler.dequeue(FlowControlHandler.java:202)
at io.netty.handler.flow.FlowControlHandler.channelRead(FlowControlHandler.java:164)
at io.netty.channel.AbstractChannelHan...
build 55 is really old, and we don't provide support for servers using plugins like the limbo suite
70a6271 Minecraft 1.21.11 release support - 4drian3d
[PaperMC/Velocity] branch deleted: feat/mc-1.21.11
Thank you so much for your contributions, keep it on!
Requested Feature
Some clients and servers backport the 1.11+ 256 character chat length to 1.8, which had worked behind Velocity until https://github.com/PaperMC/Velocity/commit/371e68607695b48117e1cd57d19c67e40384c33a and https://github.com/PaperMC/Velocity/commit/91bdcebb1aefd7eb21ef88356e4dc88a3f697cb3. Clients sending these long messages now get kicked by the proxy. This could be fixed by either completely removing the condition to enforce only 100 character chat or adding a new config option to do so
Why is this needed?
Backporting increased chat length to 1.8 is well supported. On the client-side this includes Patcher for Forge and Apollo for Lunar Client, and on the server-side this includes Hypixel and forks such as SportPaper.
Alternative Solutions
This limit is imposed by the proxy and can only be changed there
Additional Information
No response
Expected Behavior
According to the JavaDocs comment for the LoginStatus enum:
The status of the connection when the player disconnected.
The result of DisconnectEvent#getLoginStatus() should be identical whether the client disconnects on its own or the backend disconnects the client: SUCCESSFUL_LOGIN
Actual Behavior
- When disconnecting using the Minecraft client, the result of DisconnectEvent#getLoginStatus() is:
SUCCESSFUL_LOGIN - When disconnecting using the backend console (Paper), the result of DisconnectEvent#getLoginStatus() is:
PRE_SERVER_JOIN
Steps to Reproduce
- Listen to the DisconnectEvent event
@Subscribe
public void onDisconnected(DisconnectEvent event) {
this.logger.info("Current Server: " + event.getPlayer().getCurrentServer());
this.logger.info("Login Status: " + event.getLoginStatus());
}
- Log in to the server and disconnect using the Minecraft client (in-game).
- Log in to the server and disconnect the client via the backend with...
I almost feel like a config option for this is somewhat obsolete? Surely if someone doesn't want the feature they just wouldn't put the jars in the update folder?
I may be missing something obvious regarding this though.
I personally think a config option is good and that this functionality should be disabled by default, as plugins might download files into that update folder without user-consent. Sure they could also just download files directly if they are malicious but I'm thinking about cases where someone needs to use an older version for some reason (e.g. compatibility or bugs in a new version) but the plugin tries to always auto-update. (Ideally the config would even allow turning it off on a per-plugin basis)
the issue in my testing seems to be that the player getting kicked is only the player with OP
This is not working properly. When sending update action during server switch caused by backend server shutdown, player is disconnected with Network Protocol Error. Works fine when switching server using /server.
Partially deobfuscated stack trace:
Description: Packet handling error
java.lang.NullPointerException: Cannot invoke "net.minecraft.client.gui.components.LerpingBossEvent.a(net.minecraft.world.BossEvent$BossBarColor)" because "$$3" is null
at net.minecraft.client.gui.components.BossHealthOverlay$1.updateStyle(SourceFile:136)
at net.minecraft.network.protocol.game.ClientboundBossEventPacket$UpdateStyleOperation.dispatch(SourceFile:267)
at net.minecraft.network.protocol.game.ClientboundBossEventPacket.dispatch(SourceFile:91)
at net.minecraft.client.gui.components.BossHealthOverlay.update(SourceFile:112)
at net.minecraft.client.multiplayer.ClientPacketListener.handleBossUpdate(SourceFile:2067)
at net.minecraft.network.protocol.game.ClientboundBossEventPacket.```...
It seems like this PR (MultiVersionPacketRegistry) is using fastutil classes excluded by the buildscript, which you can see when trying to ping the server.
https://github.com/PaperMC/Velocity/blob/8f65a8142029717d3af09ecf82792f7345dc873a/proxy/build.gradle.kts#L85 (and potentially more)
This is still not working properly. When sending update action during server switch caused by backend server shutdown, player is disconnected with Network Protocol Error. Works fine when switching server using /server.
Partially deobfuscated stack trace:
Description: Packet handling error
java.lang.NullPointerException: Cannot invoke "net.minecraft.client.gui.components.LerpingBossEvent.a(net.minecraft.world.BossEvent$BossBarColor)" because "$$3" is null
at net.minecraft.client.gui.components.BossHealthOverlay$1.updateStyle(SourceFile:136)
at net.minecraft.network.protocol.game.ClientboundBossEventPacket$UpdateStyleOperation.dispatch(SourceFile:267)
at net.minecraft.network.protocol.game.ClientboundBossEventPacket.dispatch(SourceFile:91)
at net.minecraft.client.gui.components.BossHealthOverlay.update(SourceFile:112)
at net.minecraft.client.multiplayer.ClientPacketListener.handleBossUpdate(SourceFile:2067)
at net.minecraft.network.protocol.game.ClientboundBossEventPacket.handle```...
Expected Behavior
I set viaversions all purpur latest plugins.
The Velocity connect 1.21.11 and geyser
Actual Behavior
But below Error displeyed,and not nconnect.
[00:11:33 INFO]: [connected player] Fairy_Nakata (/192.168.11.22:49669) has connected
[00:11:34 INFO]: [server connection] Fairy_Nakata -> server1 has connected
[00:11:36 ERROR]: [server connection] Fairy_Nakata -> server1: exception encountered in com.velocitypowered.proxy.connection.backend.BackendPlaySessionHandler@49ac0fc1
com.velocitypowered.proxy.util.except.QuietRuntimeException: A packet did not decode successfully (invalid data). For more information, launch Velocity with -Dvelocity.packet-decode-logging=true to see more.
[00:11:36 INFO]: [connected player] Fairy_Nakata (/192.168.11.22:49669) has disconnected: server1 ใจใฎๆฅ็ถใซๅ้กใ็บ็ใใพใใใ
Steps to Reproduce
1.prepere purpur 1.21.10(latest)
2,set velocity
3.connect client by 1.21.11
Plugin List
Advanced-Portals-Spigot-2.5.0.jar
FoxCore
FoxGate
Geyse...
You would need to follow the advice from the error on how to see what failed, but, we don't support protocol hacks
Expected Behavior
Server should operate normally as excepted even with HAProxy enabled
Actual Behavior
With HAProxy enabled on Pterodactyl panel a server randomlly loops and takes up all the avaliable CPU (with PID limit disabled). If PID limit is enabled it gets hit and server is killed.
It loops with players online or with no players. Looping is random. Sometimes it takes a few days, sometimes just a few minutes.
Steps to Reproduce
Run Velocity server on Pterodactyl server
Enable HAproxy in the .toml configuration file
Wait
Plugin List
AutoUodateGeyser
CleanPing
Custom F3 Brand
FooodGate
ForceResourcePack
Geyser
JPremium
LuckPerms
mdMOTD
plan
SkinsRestorer
Sonar
Tebex
Velocity-hub
Voicechat
VotifierPlus
Velocity Version
[11:14:35 INFO]: Velocity 3.4.0-SNAPSHOT (git-8f65a814-b558)
Additional Information
No response
I found this slight redundancy while backporting modern forwarding to Forge 1.7.10-1.12.2, and have verified that Velocity rejects player connections if the backend server has not implemented the necessary player info forwarding flow (as it would with any modern server that doesn't have modern forwarding configured correctly).
The statement in the comment:
If the proxy is configured for modern forwarding, we must deny connections from 1.12.2 and lower, otherwise IP information will never get forwarded.
No longer seems to be true, considering Velocity's LoginSessionHandler will disconnect the player with the message velocity.error.modern-forwarding-failed if the proxy doesn't receive the velocity:player_info LoginPluginMessagePacket.
The velocity.error.modern-forwarding-needs-new-client disconnect message is also somewhat misleading, as it's on the backend server software to support modern forwarding/have modern forwarding configured correctly.
To elaborate: if you're using...
I mean, this is a weird are as protocol hacks are not something that we support; I'm dubious on the nature of removing a message which makes it fairly trivial to support a somewhat common misconfiguration that people have, protocol hacks don't tend to bump the protocol in a manner that velocity can even see it to attempt using a modern forwarding mechanism.
I am loosely open to not getting in the way of such hacks, but, it should be fairly opt in from servers doing stuff rather than removing the forward presentation which makes it clear why the connection can go on
That's quite fair, I was too deep on the topic and didn't think of things from that angle. I could see how removing that check would make things far more confusing to the average user.
Not at all married to the name, but would a config flag like this suffice?
advanced.modern-forwarding-allow-legacy-connections (defaulting to false)
Additionally, would it be acceptable to add an opt-in config flag that could move LoginPluginMessagePacket and LoginPluginResponsePackets registered version down to 1.7.2 to explicitly allow for back-ported solutions?
For example, something along the lines of:
advanced.modern-forwarding-register-legacy-login-packets (defaulting to false)
Would love to see this added! Is there any update on this?
Same idea as PaperMC/Paper#13447
Expected Behavior
For me to be able to connect every time
Actual Behavior
For a few joins in a row i get this error
[03:37:37 INFO]: [connected player] ImFascinated (/9.42.231.13:50645) has disconnected: An internal error occurred in your connection.
[03:37:37 ERROR]: [connected player] ImFascinated (/9.42.231.13:50645): exception encountered in com.velocitypowered.proxy.connection.client.ClientConfigSessionHandler@4d682691
io.netty.handler.codec.CorruptedFrameException: Error decoding class com.velocitypowered.proxy.protocol.packet.ClientSettingsPacket Direction SERVERBOUND Protocol 1.21.11 State CONFIG ID 0x0
at com.velocitypowered.proxy.protocol.netty.MinecraftDecoder.handleDecodeFailure(MinecraftDecoder.java:130) ~[server.jar:3.4.0-SNAPSHOT (git-8f65a814-b558)]
at com.velocitypowered.proxy.protocol.netty.MinecraftDecoder.tryDecode(MinecraftDecoder.java:85) ~[server.jar:3.4.0-SNAPSHOT (git-8f65a814-b558)]
at com.velocitypowered.proxy.protocol.net```...
Error generally suggests that an invalid packet was sent, general try reproducing without plugins, etc; hard to say otherwise, we can't really provide support when running in non-standard setups
Maybe we could add this as an alias for the /velocity info command and (maybe if it's missing, I haven't look it up so far) add the information about updates.
I've looked it up and it seems like Velocity already has a version information included, the only thing missing is the connection to the internet saying like "you are 5 versions behind", so maybe we could add this as well.
Ok.
The issue seems to be coming from "Enable-reuse-port" option. It seems like running pterodactyl with docker and this setting enabled, loops and overloads the CPU no matter that the system is powered by Linux OS. It does happen randomly though with no way to predict it. I narrowed it down that it can happen from anywhere as fast as 15 minutes to up to 24 hours.
Expected Behavior
A lot of classes still only include copyright information from 2025.
Actual Behavior
They should include 2026 as well.
Steps to Reproduce
Open a class like ProxyPreShutdownEvent.java and read the headder
Plugin List
Not applicable
Velocity Version
Latest
Additional Information
I'll fix this soon, I just wanted to document this correctly, thanks ๐
Fixes #1703 , Thanks ๐
Expected Behavior
hey devlopers am tired out of this error
[08:09:58 INFO]: [connected player] Gamex_Bunny has disconnected: Your connection was corrupted by the anarchy system.
[08:09:58 ERROR]: [connected player] Gamex_Bunny : exception encountered in com.velocitypowered.proxy.connection.client.ClientPlaySessionHandler@351aaad2
io.netty.handler.codec.EncoderException: java.lang.IllegalArgumentException: Invalid token
at io.netty.handler.codec.MessageToMessageEncoder.write(MessageToMessageEncoder.java:107) ~[server.jar:3.4.0-SNAPSHOT (git-372a3b28-b561)]
at io.netty.channel.AbstractChannelHandlerContext.write(AbstractChannelHandlerContext.java:827) ~[server.jar:3.4.0-SNAPSHOT (git-372a3b28-b561)]
at io.netty.channel.AbstractChannelHandlerContext.write(AbstractChannelHandlerContext.java:752) ~[server.jar:3.4.0-SNAPSHOT (git-372a3b28-b561)]
at io.netty.handler.codec.MessageToByteEncoder.write(MessageToByteEncoder.java:113) ~[server.jar:3.4.0-SNAPSH...
In our plugin, I need to cancel a channel sent by Fabric's Particle API in order to prevent a confliction between Fabric API and our packet transformers. This patch allows me to intercept the register/unregister payloads and remove the channel.
I'm not familiar with the internals, so I wasn't sure where to put this best (as putting it into the registrar directly would probably introduce destructive API changes)
This patch is required for the top header commit on this tree: https://github.com/ViaVersion/ViaVersion/tree/next/fabric-particle-workaround
Velocity not exposing channels which are handled internally is intentional, I get the desire here, but I feel that this opens up a door I'd rather not
[PaperMC/Velocity] Issue opened: #1707 Add new setting to prevent connected player errors in console
Requested Feature
Add a new config option to disable the error message when a connected player cannot connect.
Why is this needed?
Especially on big servers, the red error messages can spam the console, even when player connection messages are disabled (there is already a setting for logging connection messages)
Alternative Solutions
- donโt add a new setting and only add the config check for the log-player-connections boolean
- ignore these messages in console, wich can be very annoying or even confusing
Additional Information
The error is send here: https://github.com/PaperMC/Velocity/blob/372a3b28bd3bbaebf5934b4582dbb2feba70a93e/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java#L718
Fixes #1707
This PR adds a new config option to the velocity config (refactoring the default toml) and using the configuration value to either prevent or allow sending the error message when a connected player fails to join the backend server.
It's not handled in the configuration state at all, without my patch Velocity will just cancel/forward the packet to the server. I in general don't get the purpose of the protocol / why it still exists, as it makes things just more complicated and doesn't offer any benefits. Is there any other way I can edit the packet with internals/raw API?
Expected Behavior
No crash when using Java 25
Actual Behavior
Since I updated from Java 21 (amazon-corretto-21.0.5.11.1) to 25 (amazon-corretto-25.0.1.9.1-linux-x64), it seems that Velocity is crashing.
Here are attached the hs_err_pid and replay_pid if those help.
Steps to Reproduce
I simply left the server open with players joining it.
Plugin List
Plugins: velocity, bungeeadmintools, floodgate, luckperms, mckotlin-velocity, minimotd-velocity, myserverproxy, pinglimiter, plan, signedvelocity, velocityfriends, velocityservertp
Velocity Version
Velocity 3.4.0-SNAPSHOT (git-372a3b28-b561)
Additional Information
Even though I am not an expert, i tried to read the last lines of the replay_pid file and it seems that the last action was a netty one. It is the case in all the previous crashes that I had since switching to Java 25.
As a result, it might be related in some way to https://github.com/PaperMC/Velocity/issu
The important part is where it crashes, which is the following part of the hs_err file:
--------------- T H R E A D ---------------
Current thread (0x00007f878816dcc0): JavaThread "C2 CompilerThread0" daemon [_thread_in_native, id=3660752, stack(0x00007f875e2e4000,0x00007f875e3e4000) (1024K)]
Current CompileTask:
C2:46721945 21650 4 io.netty.util.internal.ReferenceCountUpdater::retryRelease0 (70 bytes)
Stack: [0x00007f875e2e4000,0x00007f875e3e4000], sp=0x00007f875e3df680, free space=1005k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V [libjvm.so+0x717eb6] Compile::final_graph_reshaping_walk(Node_Stack&, Node*, Final_Reshape_Counts&, Unique_Node_List&)+0x336
V [libjvm.so+0x718d8c] Compile::final_graph_reshaping()+0x23c
V [libjvm.so+0x71c659] Compile::Optimize()+0x999
V [libjvm.so+0x72087c] Compile::Compile(ciEnv*, ciMethod*, int, Options, DirectiveSet*)+0xf8c
V [libjvm.so+0x63c969] C2Compiler::compile_method(ciEnv*, ciMethod*, int, boo```...
Hello, thanks for your quick reply !
Here are some of my last crashes stacks : https://pastebin.com/hDX9qH4d
As you told me, it seems to be a JVM bug but i don't know where to get a fastdebug JVM build. Can you point me where I could get one ?
After some search this might be https://bugs.openjdk.org/browse/JDK-8361211.
So you can
- try a Java 26 Early-Access build from https://jdk.java.net/26/
- use a build from https://builds.shipilev.net/openjdk-jdk25/ (check the instructions on how to use the fastdebug build). This is only really helpful if you want to dig deeper into what's going on.
- wait until Java 25.0.2 which should be released Tuesday next week.
OK, thanks for your help ! :)
I'll just wait for the 25.0.2 release
If those where to be handled it would be to fit it into the existing path that is used in play, rather than exposing the ability to cancel this stuff; it's generally an intentional design of velocity that plugins can't intercept arbitary stuff, if you want to intercept a channel you should register it yourself so that the standard event handling works, and then you can deal with controlling if it forwards or not
Pretty sure you can't register minecraft:register itself so that wouldn't really work
I guess in this case where you care about messing with actual registrations that wouldn't be viable to expose in general, especially given that we don't really want to support stuff screwing over other stuff; For this you'd pretty much be delegated to using a packet library
Requested Feature
When using Component.translatable(key, fallback), the expected behavior is that if the key is not found in the GlobalTranslator, the fallback string should be displayed. However, in Velocity, it currently displays the empty string instead of the provided fallback string.
The following is the test code.
import com.google.inject.Inject;
import com.velocitypowered.api.command.CommandManager;
import com.velocitypowered.api.command.SimpleCommand;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
import com.velocitypowered.api.plugin.Plugin;
import com.velocitypowered.api.proxy.ProxyServer;
import net.kyori.adventure.text.Component;
import org.slf4j.Logger;
@Plugin(
id = "translatable-component-test",
name = "TranslatableComponentTest",
version = "0.0.1"
)
public class TestPlugin {
@Inject
private Logger logger;
@Inject
private ProxyServer server;
@Subsc```...
Hey, nice work!
However, I think localization is generally handled through crowdin.
https://papermc-io.crowdin.com/velocity
This would allow IDEs to show a warning when a plugin id isn't valid while you're writing it instead of during compile.
Requested Feature
add support for 1.7.2 to 1.12.2 modern forwarding with PCF
Why is this needed?
to allow the server to use a more secure modern forwarding from 1.7.2 to 1.12.2
Alternative Solutions
Ive had to compile custom code to allow the client from 1.7.2 to 1.12.2 to be able to use modern forwarding by setting locks of 1.13 to 1.7.2
https://github.com/p0t4t0sandwich/Velocity/tree/feat/modern-forwarding-legacy
edited this with more things changed
Additional Information
No response
Expected Behavior
When using a Fabric backend server behind a Velocity proxy, granting OP permissions
to a player causes the backend connection to fail.
Velocity throws a CorruptedFrameException while decoding the AvailableCommandsPacket.
This happens when the full Brigadier command tree is sent to the client after OP is granted.
The issue does not happen for non-OP players.
Steps to reproduce
- Set up a Velocity proxy
- Connect a Fabric server (Minecraft 1.21.x) as a backend
- Join the server through Velocity as a normal player
- Grant OP to the player (
/op <player>) - The player is disconnected and Velocity logs a decoding error
io.netty.handler.codec.CorruptedFrameException:
Error decoding class com.velocitypowered.proxy.protocol.packet.AvailableCommandsPacket
Direction CLIENTBOUND Protocol 1.21 State PLAY ID 0x11
Caused by: java.lang.IllegalArgumentException: Argument type identifier 57 unknown.
at com.velocitypowered.proxy.protocol.packet.brigadier.Argumen...
Valocity needs to be able to decode the packet, it can't do that with unknown data types, See the Crossstitch mod to mitigate this issue
[PaperMC/Velocity] Pull request opened: #1715 Fix ByteBuf memory leak in MinecraftVarintFrameDecoder
Reset buffer reader index on exception to prevent memory leaks when packet decoding fails.
Without this fix, if an exception is thrown during frame decoding, the buffer's reader index could be left in an inconsistent state, causing the ByteBuf to not be properly released.
This fix is designed to resolve an exploit recently being abused by a malicious actor with the intent of crashing Velocity servers for ransom.
The concerned lines were traced as being the cause of this issue by using Netty's leak detector while Velocity was being actively attacked.
This fix has been in use on Complex Gaming since January 7th with no adverse side effects.
3022793 Fix ByteBuf memory leak in MinecraftVarintFrameDec... - mxson
Add a space in between the "if" and the configuration getter.
Although I'm pretty sure this isn't a feature Velocity intends to implement in this format. At the very "best," likely a way to suppress the stacktrace, but to retain the unable to connect indicator
[PaperMC/Velocity] Pull request opened: #1716 fix: TranslatableMapper not using fallback translation
Fixes an issue where a TranslatableComponent that cannot be translated by the GlobalTranslator renders as an empty Component in the console.
Fixes #1710
IMO a config migration would be nice. Even though there is nothing to be migrated but to have the option show up for old users, unlike what happened with the rate limiter options where a at least few users where confused
My Velocity proxy also crashed after running on Java 25.0.1 for a few days. I initially thought this was an isolated case, but later restored stability by switching back to Java 21. I wonโt consider using Java 25 in the short term.
[PaperMC/Velocity] New branch created: update-deps
Make Velocity compileable with Java 25 and update some dependencies
The biggest jump would be Guava, where I'm not sure why it's on such an old version?
92b9fb6 Update more deps, include shadow change from J21 P... - kennytv
missing a nullable annotation
This should be its own section rather than having the same prefix in the root section
This should be its own section rather than having the same prefix in the root section
Ternaries for each of those would make them a bit more compact. And not sure if this means much, but this looks functionally different to the description and mods search from before where it would continue iterating responses if they're null in the current one
Giving general approval, but notes for whoever wants to merge or consider this:
- There is also https://github.com/PaperMC/Velocity/pull/1357
- There is a PR to expose the forwarding mode that wasn't merged since it's deemed more of an internal property
Hey, thanks for reviewing. I just wanted to check, are you satisfied with the design?
It's quite an old PR so I wanted to make sure it's still the right fit before I resolve the conflicts and make the minor change.
For what it's worth, I've since been running this patch in production, and it's worked quite well.
Yeah should be alright
On the ternaries, personal preference but that's an easy fix to make down the road. I don't think that should keep you from merging the pull request.
As for the difference in handling mod/description search: If you were to implement that in this code, you'd run the risk of, say, returning the player count from one server and the mod list from another, or returning the player count & mod list from a different server from the one the player is about to join, so unless someone jumps in here and says "hey I need that," I think it's fine the way it is.
I agree. When I wrote this code, I did not know that was a thing you could do. Had I known, I would've done so.
057b0ef Fixed sending ServerData packets if the descriptio... - 4drian3d
eb7d7c2 Moved pre-1.19.1 command argument validation so it... - p0t4t0sandwich
333128c Generate a new forwarding secret file if the file... - 4drian3d
9942b67 feat: PlayerChannelUnregisterEvent (#1686) - SNWCreations
ef05f3a Fix exception message formatting in command invoca... - szymon-off
9362993 [ci skip] Replaced slf4j javadocs provider with ja... - 4drian3d
1e95491 Minecraft 1.21.11 (#1690) - 4drian3d
e258ea8 bump adventure to 4.26.1 (#1697) - RealBauHD
ad171e5 Restrict empty packet frames from clients - electronicboy...
97f9f23 Use modern java features in more places - 4drian3d
7412aca Fixed sending ServerData packets if the descriptio... - 4drian3d
f75b512 Moved pre-1.19.1 command argument validation so it... - p0t4t0sandwich
b6b6b20 Generate a new forwarding secret file if the file... - 4drian3d
75d6811 feat: PlayerChannelUnregisterEvent (#1686) - SNWCreations
a046f70 Fix exception message formatting in command invoca... - szymon-off
6cc1be7 [ci skip] Replaced slf4j javadocs provider with ja... - 4drian3d
8f65a81 Minecraft 1.21.11 (#1690) - 4drian3d
4bc3f00 bump adventure to 4.26.1 (#1697) - RealBauHD
a03bd88 Restrict empty packet frames from clients - electronicboy...
[PaperMC/Velocity] branch deleted: update-deps
75ecb64 Update minimum Java version to 21 (#1649) - 4drian3d
[PaperMC/Velocity] branch deleted: update/java/21
I don't think this should be something built-in to Velocity, but rather something a plugin should do
I agree, this pr would limit the ability of modded servers to receive chat messages of any length they require
Do we consider event constructors to be part of the public API? If so, we might want to deprecate the old constructor instead of removing
Is there a reason we're keeping this and marking it as deprecated? Since it's an internal method, I think it would be okay to remove it
Mostly just didn't want to interrupt those doing strange things w/ reflection/forks straight away since it can't be as clean the paper impl
Well I have had that option enabled since it was was added and never had problems like that, I don't use HAProxy and many of your plugins though. Could you try to create a a minimal setup to reproduce the issue?
This PR covers the remaining outdated dependencies (and has been tested). It also reimplements the strictness of checkstyle not only in a general sense but also for packet-oriented classes. I simply believe that the packet-driven classes should be subject to checkstyle to ensure any future changes made or added to said classes donโt fall behind in regards to codestyle, as some other classes have represented.
Thanks for bringing this upstream! This won't have any bearing on merging, but just curious if those docs are hand-written or generated ๐
This also looks odd, and one in another class
Line break shouldn't cut the condition in half
Thanks for bringing this upstream! This won't have any bearing on merging, but just curious if those docs are hand-written or generated ๐
Thanks for the comment! Iโd say about 40% of them were generated; however, I spent a good sum of time ensuring they at least made sense but Iโll make sure to clean everything up when Iโm awake again. Took me a good sum of hours to whip this all up haha. Appreciate the kindness here!
This resolves a compiler warning when compiling Velocity. If you feel it doesnโt fit, Iโm more than inclined to toss
Also experiencing this
Pull request overview
This PR updates several core dependencies and tightens style enforcement, while adding extensive Javadoc and minor cleanups across proxy protocol packets and the public API. It also makes packet-oriented classes subject to Checkstyle by removing previous exclusions and documenting their behavior more thoroughly.
Changes:
- Bump various libraries (Netty, fastutil, JUnit, Checkstyle, toml4j) and update Javadoc configuration to target Java 21.
- Remove the Checkstyle exclusion for proxy protocol packets and reformat/annotate many packet, chat, and brigadier-related classes to satisfy stricter style rules.
- Add and refine Javadoc for many API types (events, networking, player/server info, plugin metadata) to better document behavior and extension points.
Reviewed changes
Copilot reviewed 183 out of 185 changed files in this pull request and generated 4 comments.
Show a summary per file:
||| File | Description |
| ---- | ----------- |
| proxy/src/main/r...
The Javadoc for Version.getName() incorrectly says "Gets the legacy string name of the sample player," but this method actually returns the user-facing name of the server version. Please correct the description so it refers to the server version name, not a sample player.
The constructor Javadoc for SamplePlayer mentions constructing from a Component-based name and documents the name parameter as a Component, but the signature actually takes a String name. This is confusing for API users; please update the Javadoc to describe the String parameter correctly (and, if appropriate, mention how it relates to any Component-based representation).
The class-level Javadoc appears to have been copied from FinishedUpdatePacket and does not describe CodeOfConductPacket at all (it talks about signaling completion of an update process rather than code-of-conduct data). This is misleading for API users; please update the Javadoc to accurately describe what CodeOfConductPacket represents and how it is used.
In encode, the body that writes the sound source, entity id, volume, pitch, and seed is currently inside the if (fixedRange != null) block. This means that when fixedRange is null, the packet only writes the boolean flag and omits all the required fields, producing an invalid packet on the wire. To fix this, only the buf.writeFloat(fixedRange) call should be conditional, while the remaining writes (writeSoundSource, entity id, volume, pitch, seed) should execute regardless of whether fixedRange is present.
This was a simple codestyle change, so I'll void this one. Other ones are valid
This does look valid, the closing bracket was placed incorrectly
Ah was probably the explanation that threw me off then. I'll resolve that when I'm back on. Thanks!
Noticed in https://github.com/PaperMC/Velocity/commit/7d0c002f89d1cc916fd7525bcb4f2a0f4bc31649 the javadocs still mention the old docs site, this PR just change that to the PaperMC docs.
Implement adventure's SkinSource for Player and GameProfile to allow passing instances to ObjectContents.playerHead(SkinSource).
The GameProfile implementation creates a "static" player head if the profile has any properties. Otherwise, it creates a "dynamic" player head using the profile's UUID.
The Player implementation uses its current game profile and, if the player already sent its settings, includes whether the hat should be shown.
9bfe19f [ci skip] Replace docs.advntr.dev to docs.papermc.... - Doc94
14160e1 feat: Implement SkinSource for Player and GameProf... - Emilxyz
Requested Feature
i run in following issue, the proxie server don't recognize the deactivatet online mode from cardboard log:
io.netty.channel.ConnectTimeoutException: connection timed out after 5000 ms: /127.0.0.1:25566
at io.netty.channel.epoll.AbstractEpollChannel$AbstractEpollUnsafe$1.run(AbstractEpollChannel.java:664) ~[velocity-3.5.0-SNAPSHOT-573.jar:3.5.0-SNAPSHOT (git-14160e19-b573)]
at io.netty.util.concurrent.PromiseTask.runTask(PromiseTask.java:98) ~[velocity-3.5.0-SNAPSHOT-573.jar:3.5.0-SNAPSHOT (git-14160e19-b573)]
at io.netty.util.concurrent.ScheduledFutureTask.run(ScheduledFutureTask.java:160) ~[velocity-3.5.0-SNAPSHOT-573.jar:3.5.0-SNAPSHOT (git-14160e19-b573)]
at io.netty.util.concurrent.AbstractEventExecutor.runTask(AbstractEventExecutor.java:148) ~[velocity-3.5.0-SNAPSHOT-573.jar:3.5.0-SNAPSHOT (git-14160e19-b573)]
at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:141) ~[velocity-3.5.0-SNAPSHOT-573.jar:3.5.0-SNAPSHOT...
Hybrids are not supported.
Furthermore I don't understand what you mean exactly but support is handled on the discord.
The TCP connection failed to establish, this is a network issue, the software at this point is basically irrelevant to the issue
Expected Behavior
I expect the server to be able to send the client back to configuration and bring them back to play without issue.
Actual Behavior
The server recieves an invalid packet and disconnects the client.
Error message from an unmodified vanilla server
[13:50:31] [Server thread/INFO]: notmattw (9f36238e-bee0-3e4e-9404-44efe6986143) lost connection: Internal Exception: io.netty.handler.codec.DecoderException: Received unknown packet id 12
Also error message from a Minestom server
java.lang.IllegalStateException: Packet id 0x1d isn't registered!
at net.minestom.server.network.packet.PacketRegistry$PacketRegistryTemplate.packetInfo(PacketRegistry.java:482)
at net.minestom.server.network.packet.PacketReading.readPayload(PacketReading.java:210)
at net.minestom.server.network.packet.PacketReading.readFramedPacket(PacketReading.java:187)
Steps to Reproduce
Start velocity pointing at a vanilla server with debug commands enabled, eg
java -DMC_DEBUG_ENABLED -D```...
The queue handling logic was a bit handholdy, a lot of the handling for this phase was honestly a "get it out the door"
I want to find the time to do a major version bump to just redo a whole bunch of this stuff, this is mostly intended for mitigating plugin API related things, so the queue can probably go
For your interest, our fix for this was https://github.com/hollow-cube/Velocity/commit/11f99c5517c061f962502f852cd2d322a21d39cc
I found that, for our use case, it fully worked without the packet queue, but I thought making sure it queues packets on first run was more like the expected behaviour for this functionality. I can PR this upstream if this is a reasonable change, though it probably needs some more testing with some plugins and a vanilla server.
Maybe worth a config option that is defaulted to off? Not that adding config options really works well right now, but deprecate it and let plugins deal with upgrading before I yeet it whenever somebody finds the time to do an overhaul here
I think only the outbound queue should be enabled in ConnectedPlayer#switchToConfigState.
It's been almost 3 years now
Any update on this?
Cheers, however, as mentioned, localisations need to be done through crowdin otherwise they won't be tracked properly
[PaperMC/Velocity] New branch created: l10n_dev/3.0.0
Thai should now be available on Crowdin
[PaperMC/Velocity] branch deleted: l10n_dev/3.0.0
[PaperMC/Velocity] New branch created: l10n_dev/3.0.0
Seems to be standard behavior and should not break anything.
Yea, the files saved by Velocity don't have it and it is also displayed like normal
Requested Feature
Add support for proxy_protocol to the speed configuration so that frp can obtain the real IP address.
Why is this needed?
This enables servers utilizing frp to retrieve the players' real IP addresses.
Alternative Solutions
NO
Additional Information
No response
Because of the translation I don't fully understand what "frp" means, but Velocity already has a haproxy-protocol option, is that what you mean?
ๅ ไธบ็ฟป่ฏ็ๅๅ ๏ผๆไธๅคชๆ็ฝโfrpโๆฏไปไนๆๆ๏ผไฝVelocityๅทฒ็ปๆhaproxy-protocol้้กนไบ๏ผไฝ ๆฏ่ฟไธชๆๆๅ๏ผ
frp, which stands for Fast Reverse Proxy, is a technology used to expose public ports for devices without a public IP address.
URL: https://github.com/fatedier/frp/
I hope frp can natively support Paper's proxy_protocol, just like BungeeCord does.
Because of the translation I don't fully understand what "frp" means, but Velocity already has a haproxy-protocol option, is that what you mean?
frp, which stands for Fast Reverse Proxy, is a technology used to expose public network ports for devices without a public IP address.
URL: https://github.com/fatedier/frp/
I hope Velocity can also natively support Paper's proxy_protocol, just like BungeeCord does.
Velocity has the exact same support as in Paper for the proxy protocol using the option I mentioned
Velocity ๅฏนไปฃ็ๅ่ฎฎ็ๆฏๆๅ Paper ๅฎๅ จไธๆ ท๏ผไฝฟ็จๆๆๅฐ็้้กน
ok
Expected Behavior
When a player logs in that is already logged in, the orginal connection should be disconnected correctly before connecting the player to the server again.
Actual Behavior
In rare cases with the duplicate_login event, if you time it correctly a second duplicate_login event is received from the server itself at the same time. This causes the original connection to be disconnected from the server but not from Velocity, and it's only 10-12 seconds later when the original connection times out in Velocity that the disconnect event is finally fired which then causes unexpected behavior with any plugin that does not expect this.
Steps to Reproduce
Players with high latency connections or otherwise poor connections have been the most impacted by this, as they're more likely to be disconnected and then try to reconnect before their previous connection has timed out.
I've been simulating that using a VPN to interrupt the client's connection to the server, disconn...
https://github.com/PaperMC/Velocity/issues/1691 also seems to touch on how the disconnect event firing at unexpected times can cause errant behavior in plugins that do not expect this.
From my understanding, queue plugins have no way of knowing if a player got kicked from the backend. If this config option is turned on, plugins can still stop the proxy from disconnecting the player (and instead redirecting them) since such plugins already exist (KickRedirect). I'm just suggesting this because while redirect behavior plugins exist, there is no existing solution to disable the velocity redirect behavior for ALL kicks.
I think you can try to do something like this.
@Subscribe
fun onPlayerKicked(event: KickedFromServerEvent) {
val player = event.player
val kickedFrom = event.server
val current = player.currentServer.orElse(null)?.server
if(current == null || current == kickedFrom) {
val reason = event.serverKickReason.orElse(Component.text("ะัะบะปััะตะฝะธะต ะพั ัะตัะฒะตัะฐ"))
event.result = KickedFromServerEvent.DisconnectPlayer.create(reason)
}
}
Did you find a fix? Im having the same problem with discordsrv on paper under velocity
Looking back even further, seems this has been an issue for a long time and there was even a proposed fix back for v1.1.0 in April 2020 on https://github.com/PaperMC/Velocity/issues/289 ?
As the title says.
I was having intermittent failures because of these tests when building a Velocity fork on GitHub actions.
The culprit was already identified when the tests were first written:
// TODO: The timings here will be inaccurate on slow systems.
Note that DeterministicSchedulerBackend was written partially with the help of an LLM.
Description
This PR introduces a robust Server Health Checking system and an advanced IP Filtering framework (Maintenance, Blacklist, Whitelist) to Velocity. It also adds several administrative commands to manage these systems in real-time.
Key Features
1. Server Health Checker
- Periodic Pings: Automatically monitors backend servers at a configurable interval.
- Health States: Servers are categorized as
HEALTHY,DEGRADED(high latency), orUNHEALTHY(timeout/offline). - Events: Fires a
ServerHealthChangeEventwhenever a server's status changes, allowing plugins to react (e.g., for smart load balancing). - Configuration: Preserves defaults with a new
[health-check]section invelocity.toml.
2. Advanced IP Filter Manager
- Dynamic Blacklisting: Support for individual IPs and CIDR ranges with optional reasons and durations (temporary bans).
- Whitelisting: Allows specific IPs/ranges to bypass maintenance mode.
- Maintenance Mode: A global toggle to rest...
This generally feels entirely out of scope for velocity itself and would be much better suited as a plugin, I'm not comfortable taking on this, either. Offering user commands but 0 persistence is flawed, but, we're also not really in a position to want to provide persistence, that should be on plugins to deal with.
Do you have any link to a workflow run that failed because of this? Velocity uses github actions too and does not have this issue.
I think I managed to make it fail once when my system was on fire, having time based tests is often a bit of a nightmare, having testing envs work differently to real environments is also a bit of a wildcard too
This seems fine to me - making the scheduler totally deterministic is the canonical solution to the problem, I just didn't have an incentive to deal with it.
FWIW, I would expect those tests to be most flaky on lower-end hardware and the last time I touched this, it was mostly to improve reliability but not all of it was made deterministic.
c2fd3c0 Introduce SchedulerBackend to fix VelocitySchedule... - WouterGritter
Adds an option for subdomain-matching to [forced-hosts] that falls back to suffix matching on domain boundaries when no exact match is found. This allows forced hosts to work when DNS services (e.g., Cloudflare proxied SRV records) prepend prefixes to the virtual hostname.
The problem is that Velocity does exact string matching on the virtual host for forced-hosts, so _dc-srv.xxxxx.play.example.com doesn't match play.example.com and forced host routing breaks.
This is a "rework" of this rejected PR: https://github.com/PaperMC/Velocity/pull/1497
I'd like to clear up that the use-case for this feature isn't "hiding a misconfiguration". When you proxy an SRV target's A record through Cloudflare, Cloudflare auto-unproxies it by rewriting the hostname to something like _dc-srv.xxxxx.play.example.com. This was intentional on my part since it causes casual DNS lookups on play.example.com return Cloudflare IPs, and the origin is only exposed if someone specifically queries the Minecra...
For reference, a failed job before this merge: https://github.com/GemstoneGG/Velocity-CTD/actions/runs/21911993248/job/63268303163
But again, this build is for a velocity fork (though it didn't make any meaningful change to the scheduler).
Expected Behavior
Players should not be kicked at all
Actual Behavior
Players are kicked after a minutes of being on the Code of Conduct screen
Steps to Reproduce
- Enable Code of conduct on the first connect to server set in Velocity
- Join server
- Wait on Code of conduct screen for a minute
- Get click with
Unable to connect you to servermessage
Plugin List
velocity, autoupdateplugins, floodgate, geyser, voicechat
Velocity Version
Velocity 3.5.0-SNAPSHOT (git-c2fd3c07-b576)
Additional Information
No response
Expected Behavior
Permission velocity.command.* set to false would no longer auto complete any of velocity's commands including the /velocity:callback command to the concerned players.
Actual Behavior
The /server command is fully hidden but /velocity:callback still auto complete in the chat.
Steps to Reproduce
Use a permission manager plugin such as LuckPerms and set the velocity.command.* to false for the default group.
Verify you are part of that group and not an Operator on the server (I've disabled default Operator system in LuckPerms config too).
Start typing /velocity:callback and see it auto complete.
Plugin List
LuckPerms
Velocity Version
Velocity 3.5.0-SNAPSHOT (git-c2fd3c07-b576)
Additional Information
Haven't checked much yet about what this command actualy do but since its only available with velocity: namespace it might be an internal command since its not available with just /callback
This is intentional, see https://github.com/PaperMC/Velocity/pull/1627 for details
Should allow disabling /velocity:callback auto complete by disabling the velocity.command.callback permission to the desired players.
Please read though what I've sent you.
And locking an API feature behind a permission would be really bad, you could hide it that is not wanted on the API side and you can achieve that yourself using the PlayerAvailableCommandsEvent.
Thanks i'll look into it.
VelocityไธญJoinGamePacket.javaๅฏนไบ1.7.10็ปดๅบฆID็ไผ ้ๅชไฝฟ็จ1ๅญ่๏ผ่ฟๅฏผ่ด้จๅๆจก็ป็ปดๅบฆ็็ปดๅบฆIDไผ ้่ฟ็จไธญๅ็ๆฐๆฎๆชๆญ๏ผไผ ้ไบ้ๆณๆฐๆฎ็ปๅฎขๆท็ซฏ๏ผๅฏผ่ดๅฎขๆท็ซฏๅดฉๆบใไฝฟ็จ4ๅญ่ๅค็็ปดๅบฆIDๅฏไปฅ่งฃๅณ่ฏฅ้ฎ้ขใๆไฝฟ็จไบClaudeๆฅๅๆๅไฟฎๆน๏ผๅ ไธบๆไธไผ็ผ็จ๏ผ๏ผๅพ็ไธบClaudeไฟฎๆนๅฎๆ็ๆป็ปใ
ๆๆฏๅจๆธธ็ฉGTNH 2.8.0ๆดๅๅ ๆถๅ็ฐ็ๆญค้ฎ้ข๏ผๅฝๆถๆ็ๆๅกๅจไฝฟ็จVelocity่ฝฌๅ๏ผ้่ฟVelocityๅฎ็ฐ็ฉๅฎถ็ปๅฝ้ช่ฏ๏ผๆๅจๆธธ็ฉ้ไธญๅ็ฐๅจ็งไบบ็ปดๅบฆ๏ผ็ปดๅบฆIDไธบ180๏ผไธญไธ็บฟๅๅ ๅ ฅๅฎขๆท็ซฏไผๅดฉๆบ๏ผ่่ทณ่ฟVelocity่ฝฌๅๅไธไผ๏ผๆฅ้ๆฅๅฟๆ็คบ้ๆณ็ปดๅบฆID-76ใ
In Velocity, the JoinGamePacket.java uses only 1 byte to transmit the dimension ID for 1.7.10. This causes data truncation during the transmission of dimension IDs for some modded dimensions, sending illegal data to the client and causing the client to crash. Using 4 bytes to handle the dimension ID can resolve this issue. I used Claude to analyze and modify the code (since I don't know how to program), and the image shows the summary of the modifications completed by Claude.
I discovered this issue while playing the GTNH 2.8.0 modpack. At the time, my server used Velocity for forwarding and implemented player login authentication through Velocity. During gameplay, I found that log...
I think it'll be beneficial to write some tests for this behavior.
However, this logic seems to do functionally nothing as dimension is only ever written back to a ByteBuf using ByteBuf#writeByte, which will turn this (now signed) byte into an unsigned byte anyway.
See line 401 of this file https://github.com/xphorror/Velocity/blob/c7b83326182ed24c2edb462de04364f81ada5b0b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/JoinGamePacket.java#L401
Unless somehow the packet is read as a pre-1.9.1 packet and written as a post-1.9.1 packet? If this is the case please ignore this comment. Though that seems unlikely.
Are you sure this change solves your problem?
However, this logic seems to do functionally nothing as
dimensionis only ever written back to aByteBufusingByteBuf#writeByte, which will turn this (now signed) byte into an unsigned byte anyway.
See line 401 of this file https://github.com/xphorror/Velocity/blob/c7b83326182ed24c2edb462de04364f81ada5b0b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/JoinGamePacket.java#L401Unless somehow the packet is read as a pre-1.9.1 packet and written as a post-1.9.1 packet? If this is the case please ignore this comment. Though that seems unlikely.
Are you sure this change solves your problem?
Yes,the problem fixed.Maybe I can record a video upload to youtube later.
The valuePattern indicates optional components with brackets "[port]:[forwardingmode]", but the conversion logic at line 109 splits on ":" with a limit of 4, expecting exactly 4 parts for the full format. The description says "Use <name>:<host>:[port]:[forwardingmode]" which suggests port and forwardingmode are optional, but the actual parsing logic requires that if you want to specify forwardingmode, you must include all 4 parts (name, host, port, forwardingmode). The pattern and error message should clarify this or the parsing should be made more flexible to handle name:host:forwardingmode without requiring the port.
The method has a potential NullPointerException at line 101. If serverInfo.getServerInfoForwardingMode() returns null (line 100 check), then server.getConfiguration() is called. However, the server field is annotated with @Nullable and could be null. When VelocityRegisteredServer is constructed with a null server (which is allowed by the constructor), calling getConfiguration() on it will throw a NullPointerException. Consider adding a null check for server or documenting that this method requires a non-null server to function properly.
VelocityServer velocityServer = requireNonNull(server, "server");
return velocityServer.getConfiguration().getPlayerInfoForwardingMode();
The change to include forwardingMode in equals() and hashCode() is a breaking change in the API. Previously, two ServerInfo objects with the same name and address but different (or null vs non-null) forwardingMode would be considered equal. Now they won't be. This could break existing code that relies on ServerInfo equality for lookups, comparisons, or use in collections. While this change makes logical sense for the new feature, it should be clearly documented as a breaking change or reconsidered to maintain backward compatibility. Consider whether forwardingMode should be part of the identity of a ServerInfo object or just a configuration detail.
The error message says "You don't have a forwarding secret set. This is required if you are using MODERN or BUNGEEGUARD forwarding modes." but it doesn't specify which server has the problematic configuration. Consider including the server name (entry.getKey()) in the error message to help administrators identify which specific server needs attention. For example: "Server 'servername' uses MODERN/BUNGEEGUARD forwarding mode but you don't have a forwarding secret set."
logger.error("Server '{}' uses MODERN or BUNGEEGUARD forwarding mode but you "
+ "don't have a forwarding secret set. This is required for security.",
entry.getKey());
The example values in the default configuration show forwarding modes that may not align with a typical setup. Setting "factions" to MODERN and "minigames" to LEGACY seems arbitrary. Consider either using all three servers with null/INHERIT mode (demonstrating the default behavior), or adding comments to explain why different modes are shown. This will help users understand when and why they should set per-server forwarding modes rather than just copying these examples.
The comment on lines 78-79 doesn't explain the new per-server forwarding mode feature. Users seeing the new syntax for the first time won't understand what "forwarding-mode" means or when they should use it. Consider expanding the comment to briefly mention both syntaxes and that forwarding-mode is optional, with a reference to the documentation or a note that null/omitted values inherit from the global player-info-forwarding-mode setting.
# Configure your servers here. Each key represents the server's name.
# You can use the short form, where the value is the IP address and port to connect to:
# lobby = "127.0.0.1:30066"
# or the object form:
# factions = { address = "127.0.0.1:30067", forwarding-mode = "MODERN" }
# In the object form, address is the IP/port and forwarding-mode is optional; if it is
# omitted or set to null, the server inherits the global player-info-forwarding-mode
# setting defined above. See the Velocity documentation for more details.
Pull request overview
This PR introduces per-server player info forwarding mode configuration, allowing each backend server to use a different forwarding mode (MODERN, LEGACY, BUNGEEGUARD, or NONE) instead of inheriting the global proxy-wide setting. This enables mixed-version networks where some servers (e.g., 1.12) require LEGACY forwarding while others (e.g., Fabric 1.21) require MODERN forwarding.
Changes:
- Added new
ServerInfoForwardingModeenum andBackendServerConfigrecord to the API for per-server configuration - Extended configuration syntax to support both classic string format (
server = "address:port") and new object format (server = {address = "...", forwarding-mode = "..."}) - Modified
ServerInfoto include an optional forwarding mode field, with corresponding updates to equals/hashCode/toString methods
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 7 comments.
Show a summary per file:
||| File | Description |...
The goal of this PR was to make progress on a plugin update folder for Velocity.
Tasks:
- [x] Initial implementation
- [ ] Discuss nullability annotation for
VelocityConfiguration#getUpdateFolderName - [ ] Discuss default config value
- [ ] Discuss what the config value should be to entirely disable the update folder
- [ ] Test implementation
closes https://github.com/PaperMC/Velocity/issues/809
based on https://github.com/PaperMC/Velocity/pull/842
Before marking this as ready for review I wanted to discuss the 3 topics mentioned in the tasks list, so any discussion regarding these would be greatly appreciated.
i believe an empty string would be the best way to go about disabling it, same as it is done in other softwares
update-folder = ""
i believe an empty string would be the best way to go about disabling it, same as it is done in other softwares
update-folder = ""
I completely agree, that's what my head initially went to. Wasn't sure if there was a different practice in toml as I've not worked with it before :)
I'll adjust that one
I also noticed that in most places in the config object it seems like the nullable annotation is not used so I'll remove it unless suggested otherwise for VelocityConfiguration#getUpdateFolderName
I also noticed that in most places in the config object it seems like the nullable annotation is not used so I'll remove it unless suggested otherwise for
VelocityConfiguration#getUpdateFolderName
technically the name is not nullable, as it is an empty string (and should be checked against being empty, not null) in the update-folder = "" syntax, so marking it as @Nullable would be wrong.
technically the name is not nullable, as it is an empty string (and should be checked against being empty, not null) in the
update-folder = ""syntax, so marking it as@Nullablewould be wrong.
That's true, currently it was requiring being set to null to disable it, I'll make these changes now. I am also going to opt for.updateas default for now as that is my personal preference and what I think makes most sense.
should also include a @param for the update dir
why arenโt we doing this check for the update directory too?
imo either the name suffix should be removed or the config key should have the name suffix as well for consistency between those two
same here, refer to the comment om the lines above
but thinking about this more; the getter can have the suffix for more clarity ig
Expected Behavior
Players connect to server through Velocity successfully.
Actual Behavior
Players can't connect to server with following errors in Velocity:
[16:24:56] [Netty epoll Worker #3/ERROR] [com.velocitypowered.proxy.connection.MinecraftConnection]: [server connection] Player-> server: exception encountered in com.velocitypowered.proxy.connection.backend.BackendPlaySessionHandler@2661ba29
io.netty.handler.codec.CorruptedFrameException: Error decoding class com.velocitypowered.proxy.protocol.packet.AvailableCommandsPacket Direction CLIENTBOUND Protocol 1.20 State PLAY ID 0x10
at com.velocitypowered.proxy.protocol.netty.MinecraftDecoder.handleDecodeFailure(MinecraftDecoder.java:130)
at com.velocitypowered.proxy.protocol.netty.MinecraftDecoder.tryDecode(MinecraftDecoder.java:85)
at com.velocitypowered.proxy.protocol.netty.MinecraftDecoder.channelRead(MinecraftDecoder.java:60)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHand```...
Install CrossStitch. Literally documented in the FAQ: https://docs.papermc.io/velocity/faq/#argument-type-identifier-unknown
I opted for the suffix for clarity in the code but didn't think that same clarity was necessary in the config file. Happy to adjust either if needed though
This PR introduces PermissionFunction#getPermissionMap, and delegates like [Connected]Player#getPermissionMap.
I would like to see this be a feature of Velocity, because I'm currently trying to optimize a bit of code that uses the Velocity permission API:
private int getTimeoutInSeconds(Player player) {
for (int i = 86400; i > 0; i--) {
if (player.hasPermission("velocity.queue.timeout." + i)) {
return i;
}
}
return -1;
}
Of course having up to 86.400 permission checks is not good, even if it's just a one-off, and especially because we don't know how the permission provider implements this (each call might reach out to a redis/SQL db).
Unfortunately because lots of servers are already relying on being able to specify a permission like this, it's not trivial for me to fix this issue by reducing the amount of permission checks. Ideally I'd like to see Velocity and permission providers like LuckPerms expose the permission map, as I'm sure I'm no...
This is something permission plugins would need to weight in on, but really, this is just abuse of permissions, basically every single competent permission plugin has its own mechanism for storing a proper K->V for this stuff
this is just abuse of permissions
I assume you're referring to the hasPermission call in a giant for loop, if so, I agree so this needs to be fixed.
It would be good to see what permission plugin devs have to say, but we can also look at the bukkit api which already contains a similar feature with PermissibleBase#getEffectivePermissions.
BungeeCord has CommandSender#getPermissions.
I'm not too familiar with fabric, and if this is a feature fabric explicitly supports or not, but LuckPerms also exposes similar functionality in their fabric implementation here. So I think there's president for permission plugins (at least LuckPerms) wanting/trying to expose this information....
using permissions themselves to define what is essentially a KV is the abuse
I know that several other implementations of permissions expose such a feature, and that is why plugins like LP generally have some means of trying to populate a list of those values to appease the fact that they're often hijacking an existing implementation; I want to see what plugin devs have to say moreso on the ABI rather than the existence of such a thing, I would ideally rather have some 3rd party vault replacement which can offer abstractions for what really should be the proper solution here, however
using permissions themselves to define what is essentially a KV is the abuse
I see. I've read through the LuckPerms docs, and it looks like for this usecase their meta system would be a perfect fit.
int timeout = user.getCachedData()
.getMetaData(qo)
.getMetaValue("queue.timeout", Integer::parseInt)
.orElse(0);
Would be set with a command like
/lp user <name> meta set queue.timeout 120
I guess it would be out of the question to provide this functionality through a Velocity-native API. Something like what Vault accomplished would probably be the ideal solution here.
Though, that's for my specific use-case. I think it's still worth while to see if we can merge a feature similar to what I'm proposing here, exposing the permission map.
@lucko I wonder what your thoughts on this are
@4drian3d do you mind elaborating on your decision? Does anyone else still have a say in this? Another maintainer talked about getting the view of permission plugin maintainers, I've pinged the head maintainer of the largest permission plugin and we haven't even heard back yet.
@4drian3d do you mind elaborating on your decision? Does anyone else still have a say in this? Another maintainer talked about getting the view of permission plugin maintainers, I've pinged the head maintainer of the largest permission plugin and we haven't even heard back yet.
It seems to me that what you want to do is add an API to Velocity so that you can use a LuckPerms feature without relying directly on LuckPerms. But you have to keep in mind that not everyone uses LuckPerms (even though it is one of the best and most popular permission plugins), and that there may be other permission plugins that do not necessarily use a simple key-value system for their permissions, but may declare other types of conditions to represent them.
Also, you are giving examples of platforms that are not known for having such good API infrastructure, placing many limitations on what developers can create.
For your specific use, it is best to create an abstraction in your project that can optimi...
My thoughts (for what they're worth):
- Using permissions to represent a KV pair is not great, most permissions plugins have "metadata" or "options" concepts that are designed for this sort of data (in LP for example
/lp user lucko meta set queue.timeout 100) - Meta/options probably do not belong in the Velocity
PermissionFunctionAPI, but not my call to make (obviously) - Exposing a
Map<String, Boolean>goes against the original aims of Velocity's permissions API (https://github.com/PaperMC/Velocity/pull/41), which was to make as few assumptions as possible about how permission checks might be performed/evaluated by the implementation. The thinking was that this would allow permission plugins be creative and do useful things like wildcards, regex permissions, shorthand/glob syntax, etc without breaking any API contracts. That was my view ~8 years ago and it hasn't changed. ๐ I took the same approach with fabric-permissions-api.
Thank you lucko, loud and clear.
Obviously introducing meta getters in the Velocity permission API is not a good idea. But I'm wondering how the Velocity team looks at exposing a separate, generic, meta api for players with a generic MetaHolder?
One of Velocity's strengths I think is that its stateless, at least between reboots. But obviously there's the need to keep some kind of state, hence the permission API. It might not be that far of a fetch to also include a meta system here? Again, leaving it up to plugins like LP to implement this.
I mean, the permission API inside of Velocity is pretty minimal, we didn't really want to impose any API decisions onto plugin devs and figured either everybody would just back something like LP or the community would re-vault; there was just a minimal acceptance of velocity itself needing to do permission lookups for the few builtins we provided, as well as plugins are going to need to do permission lookups too.
All of the methods you linked to from other systems having such methods aren't raw permission APIs by the platform, they're APIs for the platforms implementation of a permission system, and so LP has to implement that stuff as the platforms implementation dictated it; if any API expansion to velocities permission stuff came, it would need to be spearheaded by permission plugin devs for a reason (hence why I said that this really needs to be checked and back by permission plugin devs)
Velocity not dictating this kinda stuff, and being stateless in general, is part of our...
as well as basically being highly restricted in the type of information they return, which is generally just not API I really want to design
That would not necessarily have to be the case of course. Look at Paper's PersistentDataContainer, they solved it quite well by providing some primitive data types, whilst allowing plugin devs to map any type they'd like onto a String/int/long (array) which means basically everything can fit in there. And that's while Paper also had to solve the issue of storing this data. Velocity doesn't have this; it'd just need to pass custom types along to the underlying plugin so they can deal with it. But that's another question. Do we want to force plugin devs to have to worry about any generic type, or should we just limit it to the Java primitives.
I still think it's worth it to explore something like a MetaHolder API interface for Velocity. However as that's entirely different than what this PR is proposing I'm closing the PR for now.
I think Velocity's update folder should mirror the Paper update folder's name (update without a dot prefix).
Also why does this need config option? I don't see why the average admin would need to change this and for advanced setups a system property is better suited IMO.
I also don't get why we would create the update folder by default or why you don't utilize Java's Files class and instead use #toFile.
I think Velocity's update folder should mirror the Paper update folder's name (update without a dot prefix).
The dot prefix acts as a way of keeping the folder at the top of the directory list and separates it from being mixed in with the plugin folders. I personally think it makes the update folder much more accessible and easy to use, which is why I set it as the default. I would go as far to say that Paper could also benefit from changing the default to include the prefix.
Also why does this need config option? I don't see why the average admin would need to change this and for advanced setups a system property is better suited IMO.
I personally think a config option is nice to have for people who prefer different formats or languages. It could use a system properpty but I don't really think this being a config option has any drawbacks
I also don't get why we would create the update folder by default or why you don't utilize Java's Files class and instead use #toFile.
I...
The dot prefix acts as a way of keeping the folder at the top of the directory list and separates it from being mixed in with the plugin folders. I personally think it makes the update folder much more accessible and easy to use, which is why I set it as the default. I would go as far to say that Paper could also benefit from changing the default to include the prefix.
That makes sense, thank you for explaining.
I personally think a config option is nice to have for people who prefer different formats or languages. It could use a system properpty but I don't really think this being a config option has any drawbacks
I don't get how different languages/formats matter here. For the average admin it is that folder and the folder being standardized also simplifies debugging for other people.
I am happy to change this if needed
Ofc it is not needed, IMO it's better to use the NOI though, as that is the more modern and cleaner solution.
I don't get how different languages/formats matter here. For the average admin it is that folder and the folder being standardized also simplifies debugging for other people.
That's fair and very true. I guess it's almost like if Paper added a config option for .paper-remapped which would be unnecessary. With system properties the option would still be there. Would we stick to a single velocity.update-folder-name where an empty string disables the update folder or do you think a second velocity.disable-update-folder would be suitable?
Well IMO I think we don't need to disable the update folder if we just don't auto create it, no?
Well IMO we don't need to disable the update folder if we just don't auto create it, no?
I based the need to disable off of discussion in the other pr regarding this topic
Well IMO we don't need to disable the update folder if we just don't auto create it, no?
I based the need to disable off of discussion in the other pr regarding this topic
Well then I think we might want a config section to disable it for individual plugins, but it also more seems like something for plugin authors to handle. If they are truly malicious they can do anything and if not then users should either raise an issue or search for an alternative. Also this should only become an issue after this feature is introduced, no?
Well then I think we might want a config section to disable it for individual plugins, but it also more seems like something for plugin authors to handle. If they are truly malicious they can do anything and if not then users should either raise an issue or search for an alternative. Also this should only become an issue after this feature is introduced, no?
In that case, I think sticking to just an empty string to disable is probably suitable enough as it doesn't require any extra options.
Looks like these 2 got mixed up
map(0x4F, MINECRAFT_1_21_9, false),
map(0x51, MINECRAFT_26_1, false));
You introduced a line break here and in another place. Further down there are some formatting changes, too.
Should probably do a config migration to disable the update folder for older setups as there's the chance that some systems/forks implemented their own version which could break
Should probably do a config migration to disable the update folder for older setups as there's the chance that some systems/forks implemented their own version which could break
How would we approach that for the system property route?
Although, any forks should be aware of what they are merging so I would personally say responsibility falls on them to make sure they aren't merging duplicate features/incompatibilities.
For anyone else that runs in to this and wants to work around the problem, lowering the velocity timeout to 18 seconds means that Velocity will always forcibly timeout and disconnect the orphaned connection prior to the very narrow window in the 19-20 seconds range where it's possible to trigger the out of sequence / misfiring duplicate_player login events issue.
Expected Behavior
This method should'nt be called.
Actual Behavior
This method does get called, possibly resulting in undesired VelocityBossBarImplementation#viewerDisconnected calls.
For reference, the entire ConnectedPlayer#disconnected method:
public void disconnected() {
for (final VelocityBossBarImplementation bar : this.bossBars) {
bar.viewerDisconnected(this);
}
}
Steps to Reproduce
Add a printline/log statement in ConnectedPlayer#disconnected, join the proxy with minecraft account A, try to re-join the proxy with the same account.
The second connection will fail, and ConnectedPlayer#disconnected still gets called.
Plugin List
n/a
Velocity Version
Compiled from latest commit e0db25664fc82eabd9fde5aac22a2311a9765975 + the log statement in disconnected().
Additional Information
This currently isn't an issue, as bossbars won't be registered to the ConnectedPlayer. However if more logic ever gets added to this method this might be an...
Expected Behavior
Players should be able to switch servers without timing out
Actual Behavior
Sometimes players are randomly stuck inbetween the PlayerEnterConfigurationEvent and PlayerEnteredConfigurationEvent when switching between servers.
They do enter the "Reconfiguring"-phase clientwise, but Velocity seems to never actually put them into the reconfig phase, leading to them timing out. See below for what I tried for debugging.
Steps to Reproduce
This happens randomly for some (but not all) players, both vanilla users and people with mods. It doesn't happen everytime, just rarely.
For debugging, I have listened on Velocity to all the config events, and the PlayerEnterConfigurationEvent is fired. I then dug into client's NMS and added logging there too (primarily in (mojang mapped) ClientPacketListener#handleLogin and ClientPacketListener#handleConfigurationStart):
Client log when the timeout happened: https://mclo.gs/kU6CX7m
Proxy log when the timeout happened:...
We are experiencing the same issue on our network and can confirm the behavior described here.
Setup
Velocity 3.4.0
Backend servers: PaperMC 1.21.7
Minecraft client versions: mostly 1.21.7-1.21.10
Proxy network with multiple backend servers (lobby, gameplay servers)
Resource pack handled via server plugins (e.g. ItemsAdder)
Observed behavior
Players sometimes get stuck in the "Reconfiguring..." phase when switching between servers through the proxy. From the client perspective they clearly enter the configuration phase, but they never actually complete it and eventually time out.
More details:
- This happens randomly and not for every player
- Both vanilla clients and modded clients (e.g. LabyMod) are affected
- For us it only happens during server switches, never during normal gameplay
- Players can switch servers many times successfully and then suddenly hit this issue on the next switch
- Other players may switch servers at the same time without any problem
- When this happens, t...
@RootException Since you seem to be having the exact same issue, would you mind DMing me on Discord? My name there is mfnalex - maybe we can narrow it down together
We are also having the exact same issue, we have 1.21.11 and 1.8.9 backend servers but have no server resource packs.
(I'm not a team member too.) I was also experimenting with implementing a per-server forwarding configuration and came across this PR.
I noticed that there are still 3 calls to getPlayerInfoForwardingMode() which assume the forwarding mode is a global setting:
- https://github.com/MarcoLvr/Velocity/blob/dfddfaad0e188c7f621f56964031ebd6182c4ed9/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java#L88
- https://github.com/MarcoLvr/Velocity/blob/dfddfaad0e188c7f621f56964031ebd6182c4ed9/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java#L146
- https://github.com/MarcoLvr/Velocity/blob/dfddfaad0e188c7f621f56964031ebd6182c4ed9/proxy/src/main/java/com/velocitypowered/proxy/connection/client/HandshakeSessionHandler.java#L150
These calls are no longer valid after introducing per-server configuration and should instead use getConfiguredPlayerInfoForwarding(). (It might also require changes to MinecraftConnection,...
Missing changes:
ResourcePackResponsePacket (0x30 -> 0x31)
ClientboundSoundEntityPacket (0x72 -> 0x74)
ClientboundStopSoundPacket (0x75 -> 0x77)
Same, backend servers ranging from 1.8.8 - 1.21.11 with 2-3 resource packs.
as mentioned, there is already an issue open for this, issue si that I cannot reproduce it, generally need packet flow information from the proxy on what is being sent between the proxy and the server, and the proxy and the client; all I can guess at this point is that some communication is getting stuck somewhere, but it's hard to know where; knowing that some events do fire and some don't kinda helps, need to get back in tune with the logical flow here, however
as mentioned, there is already an issue open for this, issue si that I cannot reproduce it, generally need packet flow information from the proxy on what is being sent between the proxy and the server, and the proxy and the client; all I can guess at this point is that some communication is getting stuck somewhere, but it's hard to know where; knowing that some events do fire and some don't kinda helps, need to get back in tune with the logical flow here, however
Is there any setting we could enable to h elp with debugging? I have of course already tried to log packets but obviously it resulted in a gigabyte of "PlayerMovement" and "Particle" packets etc lol
There are no settings for diagnosing this. That's part of the headache, is that the only real thing that would be helpful at this point is packet logs to be able to validate what is/isn't being sent, PlayerEnteredConfigurationEvent is odd, because that is fired somewhat directly in response to the client sending a configuration_acknowledged packet
general flow here is that the target server sends the login success, we then start the jump over,
clear server state > PlayerEnterConfigurationEvent > send start_configuration; At this point the client should send us back a configuration_acknowledged which should trigger a few things, almost immediately, PlayerEnteredConfigurationEvent; what is the players active session handler at the point that the connection dies?
Expected Behavior
Proxies of a large network I'm working for were constantly being restarted due to OOM kills. I highly suspect this is due to a malicious decompression attack.
I had added the following logs in MinecraftCompressDecoder#decode:
if (claimedUncompressedSize > UNCOMPRESSED_CAP * 0.95) {
LOGGER.warn("Received a packet with a large uncompressed size: {} bytes ({}% of the {} byte cap) from {}",
claimedUncompressedSize,
(int) (claimedUncompressedSize * 100.0 / UNCOMPRESSED_CAP),
UNCOMPRESSED_CAP,
ctx.channel().remoteAddress());
}
When we were under attack we got spammed by the following logs:
[17:36:45 WARN]: Received a packet with a large uncompressed size: 8380416 bytes (99% of the 8388608 byte cap) from /x.x.x.x:16643
All from the same IP address, all with the same packet size. Moments later the proxy got OOM killed.
When we blacklisted this IP at the firewall level the proxies stayed alive.
I've implemented the following fix on a...
probably some plugin message packets + plugin what process PluginMessageEvent async or abusing loginPluginMessages queue.
or you have compression disabled between proxy <--> backend, so these buffers are stored inside netty's internal write queue. Looks like configuration handlers do not have back pressure handling (writabilityChanged()), what propably should help to mitigate that type of attack.
Fixes checkstyle (broken by https://github.com/PaperMC/Velocity/commit/e8b64aa6c09edb0846dc06687307a4343637224e) and adds size checks to more config phase packets. Additionally, also implements some safeguards to ensure all packets during login/config states are known and the inbound packet queue doesn't grow too large in size.
Fixes #1740.
Prevents ConnectedPlayer teardown from running for a rejected duplicate-login attempt by only taking teardown ownership after the duplicate-login gate passes.
Tests:
- Added a regression test to verify a rejected duplicate login does not reach teardown/unregister logic
- Added a test to verify owned players still teardown on disconnect
I was able to recreate the attack we we're experiencing by sending large unknown packets and large discardedpayload packets during the ClientConfigSessionHandler phase. https://github.com/PaperMC/Velocity/pull/1743 fixes this attack, now it immediately disconnects the client.
velocity.log-server-backpressure already exists and was only checked by BackendPlaySessionHandler and used in BackendPlaySessionHandler#writabilityChanged, now every implementation of writabilityChanged() logs, and this PR adds the missing implementations for C[onfigSessionHandler and ClientConfigSessionHandler.
There are 12 classes that implement MinecraftSessionHandler. Should we implement writabilityChanged() in all 12 of them? Before this PR, only 2 classes implemented this, and after this PR only 4 classes implement the method. Was there any reason for omitting this method in some (most) session handlers?
Most of the other handlers don't have another connection directly involved with them, so we don't need to worry about telling the other side to stop doing stuff as there is no other side
Is there anything else that might hold this PR back?
And is it possible to approve the PR workflow? Not quite sure how that works but thought I'd ask :)
Requested Feature
Please add this Feature
Why is this needed?
It is very much needed
Alternative Solutions
not really, no
Additional Information
No response
@bencodess Velocity supports 1.21.11 since december, download the latest version at https://papermc.io/downloads/velocity
I like the implementation
The only issue I see is the folder name, since on some operating systems, putting a . at the beginning of a folder/file name hides it, so I'd prefer to keep a default similar to the one in Paper
I like the implementation The only issue I see is the folder name, since on some operating systems, putting a
.at the beginning of a folder/file name hides it, so I'd prefer to keep a default similar to the one in Paper
Very good point, I hadn't considered that, I've just pushed that one.
Only other thing that I have just thought - could it be worth adding a getUpdateFolderName API method to VelocityServer?
This addresses the proxy side of #1723.
The issue report points at queued play traffic being replayed after the server sends the client back to configuration. On the connected PLAY -> CONFIG path, Velocity was still treating the transition too much like a normal play connection. That left two problems:
- it could queue serverbound play traffic and replay it after the handoff
- it could still forward generic/unknown client packets even when the backend was no longer actually in PLAY
these changes do three things:
- use outbound only queueing for connected PLAY -> CONFIG reconfiguration
- only forward generic/unknown client packets when the backend is open, phase complete, and actually in PLAY
- only forward keepalives when client and backend states match, and only in CONFIG or PLAY
It should be noted that while testing this, I found a second bug on the backend side in Paper where the keepalive tracker survives listener handoff from PLAY to CONFIG, which can leave a stale...
Hello!
I took a peek into this and it turned out to be two separate problems.
The first one is on the Velocity side, which matches the original suspicion in this issue. On the connected PLAY -> CONFIG path, Velocity was still using full play queueing semantics and was too trusting about forwarding client traffic back to the backend. (serverbound play traffic could be replayed after the handoff, and generic packets could still be forwarded even when the backend was no longer actually in PLAY.)
See #1747- It switches this path to outbound only queueing, keeps generic/unknown forwarding gated on the backend actually being in PLAY, and only forwards keepalives when client and backend states match.
That being said, the patch fixed the proxy side issue, but it did not fully explain the timeout on its own. While testing it, I was able to locate a second bug in Paper- the keepalive tracker is carried across listener handoff from PLAY to CONFIG. Under latency, the configuration listener can...
small followup-
The timeout path ended up being even more specific than I thought from the earlier proxy debug logs:
On the failing repro, the backend sequence was:
- the PLAY listener issued keepalive A
- listener handoff moved the player into the CONFIG listener, but the old pending keepalive expectation was still carried over
- the CONFIG listener issued keepalive B
- the backend received reply B
- the backend rejected B as stale/out-of-order, because the inherited pending expectation was still A
See PaperMC/Paper#13712 for fixes + explaination.
With that Paper patch applied, I have not been able to reproduce the timeout anymore, including with added latency. Tested with 0ms, 50ms, 100ms, 500ms, 800ms.
Just encountered this today with the mod Roughly Enough Items Packet sent for class com.velocitypowered.proxy.protocol.packet.PluginMessagePacket was too big (expected 229378 bytes, got 635406 bytes)
You can use -Dvelocity.max-plugin-message-payload-size= to set the maximum allowed payload size, this is now constrained to the vanilla protocols maximum size by default
You can use
-Dvelocity.max-plugin-message-payload-size=to set the maximum allowed payload size, this is now constrained to the vanilla protocols maximum size by default (and is entirely unrelated to this issue)
You're the man thank you so much fixed it immediately I dont know how I missed that flag. I appericiate the help and fast response ๐
I don't like how a velocity.update-folder-name system property of "" needs to be set in order to disable this feature. That sounds to me like an empty folder name, which is more likely to refer to the "current directory" (whatever this might be, I would assume the plugins/ "root" folder with no prior knowledge), instead of "no directory" / "disable the feature", and would need to be documented elsewhere. Even still, it won't be clear to someone reading startup parameters what this feature does when set to an empty string, and that they should look up the docs.
I think Velocity's update folder should mirror the Paper update folder's name (update without a dot prefix).
See PluginInitializerManager.java#parse
Paper also uses the "update" (no dot) folder, but it gets it from the configuration. If we really want to mirror how Paper does things (which is not a bad thing, I think), we should also get this value from the config. An advantage of this is that we can add a comment expl...
I don't like how a velocity.update-folder-name system property of "" needs to be set in order to disable this feature. That sounds to me like an empty folder name, which is more likely to refer to the "current directory" (whatever this might be, I would assume the plugins/ "root" folder with no prior knowledge), instead of "no directory" / "disable the feature", and would need to be documented elsewhere. Even still, it won't be clear to someone reading startup parameters what this feature does when set to an empty string, and that they should look up the docs.
I think whether a second system property is added or not an empty string would have the same effect on the feature nonetheless. I personally am indifferent on whether a second system property is added or not. If someone wants to disable the feature they are likely to search the docs so will either find the system property and information regarding disabling it.
Personally, I think this method is somewhat unnecessary. It would be an oversimplification of a method call thatโs already straightforward, and very few people would actually need it (not to mention that it is exclusive to the proxy module, which is not normally accessible)
Most places where Boolean#getBoolean(String) (helper to convert a system variable to a boolean) is called, it's a static field.
private static final String UPDATE_FOLDER_NAME =
System.getProperty("velocity.update-folder-name", "update");
I think this can be fixed even better by only ever instantiating ConnectedPlayer after VelocityServer#canRegisterConnection returns true. This avoid ever creating a BossBarManager/ChatQueue/whatever (this is done in ConnectedPlayer's constructor).
VelocityServer#canRegisterConnection currently consumes the ConnectedPlayer, but only ever checks its username and UUID. We can consume a com.velocitypowered.api.proxy.player.PlayerInfo instead, which is effectively a record of String username, UUID uuid, or just consume the username/UUID to perform the check.
I think this can be fixed even better by only ever instantiating
ConnectedPlayerafterVelocityServer#canRegisterConnectionreturns true. This avoid ever creating a BossBarManager/ChatQueue/whatever (this is done in ConnectedPlayer's constructor).
VelocityServer#canRegisterConnectioncurrently consumes theConnectedPlayer, but only ever checks its username and UUID. We can consume acom.velocitypowered.api.proxy.player.PlayerInfoinstead, which is effectively a record ofString username, UUID uuid, or just consume the username/UUID to perform the check.Edit: The only issue is that we won't have access to
ConnectedPlayer#disconnect0then. This method only references the VelocityServer instance and theconnection(mcConnectionin AuthSessionHandler's context). Maybe we can pull this method intoMinecraftConnection, and haveConnectedPlayer#disconnect0just call this method on it's ownconnectionto avoid duplicate code?Edit # 2: The canonical solution is to use
G...
I needed it for my server, so why not share it with the world.
I'll leave it up to the maintainers whether or not we need unit tests in the second PR, or @ZECHEESELORD if you have the time feel free to cherry pick my commits into this PR and adapt the tests that you already have in place.
I'll leave it up to the maintainers whether or not we need unit tests in the second PR, or @ZECHEESELORD if you have the time feel free to cherry pick my commits into this PR and adapt the tests that you already have in place.
Thanks- Iโll fold your commits into #1744 when I get a chance (and then adapt the tests, so we have regression coverage)
Expected Behavior
It should resolve the localhost into ::0 as the other program does.
Actual Behavior
It has an unresolved InetAddress now.
Steps to Reproduce
- Add
exampleserver = 'some-machine-name:25565'in[servers]section ofvelocity.toml. - Try to access the
ServerInfo#getAddress()ofexampleservervia any plugins in Velocity. - We have an unresolved
InetAddress.
Plugin List
Velocity Version
[15:55:57 INFO]: Velocity 3.5.0-SNAPSHOT (git-d11511c1-b584)
[15:55:57 INFO]: Copyright 2018-2026 Velocity ContributorsใVelocity ไปฅ GNU ้็จๅ
ฌๅ
ฑ่ฎธๅฏ่ฏ็ฌฌไธ็ๆๆใ
[15:55:57 INFO]: PaperMC - GitHub
Additional Information
Ref: https://github.com/PaperMC/Velocity/blob/d11511c18499497e7f7186211b109ef395b44acd/proxy/src/main/java/com/velocitypowered/proxy/util/AddressUtil.java#L44-L58
Why didn't we always resolve the hostname?
This PR fixes #1750. It will resolve all the hostnames in the configuration.
We're resolving in bind before, and [servers] are not.
validate() now resolves hostnames, but the error message still says โvalid IP addressโ. Since hostnames are now accepted/resolved, update the message to refer to โaddressโ or โhostname/IPโ to avoid misleading users.
logger.error("'bind' option does not specify a valid address (hostname or IP).", e);
validate() now triggers DNS resolution for bind and every configured server. This can block startup/reload on slow DNS and also duplicates lookups later when servers are registered. Consider separating โparse onlyโ vs โparse+resolveโ, or caching the resolved InetSocketAddress during config load so validation doesnโt repeatedly hit DNS.
Same as bind: this validation error message says โvalid IP addressโ, but [servers] values can now be hostnames. Update the wording to โaddressโ / โhostname/IPโ so config errors are accurate.
parseAndResolveAddress can throw IllegalArgumentException (e.g., from URI.create(...)), but this converter only catches IllegalStateException. Catch IllegalArgumentException as well (and ideally include the original exception as the cause) so invalid --add-server values are consistently reported as ValueConversionException.
} catch (IllegalArgumentException | IllegalStateException e) {
throw new ValueConversionException(
"Invalid hostname for server flag with name: " + split[0], e);
Given this method now drives config/server address resolution (and behavior changed vs the old parseAddress), adding a small unit test for hostname parsing + default port handling would help prevent regressions.
Pull request overview
This PR addresses #1750 by ensuring server addresses defined via configuration/CLI are parsed using a resolving address parser so ServerInfo#getAddress() no longer returns an unresolved InetAddress when hostnames are used.
Changes:
- Removed the non-resolving
AddressUtil.parseAddressand switched call sites toAddressUtil.parseAndResolveAddress. - Updated config validation and server registration paths to use the resolving parser for both
bindand[servers]entries. - Updated CLI
--add-serverparsing to use the resolving parser.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 6 comments.
| File | Description |
|---|---|
| proxy/src/main/java/com/velocitypowered/proxy/util/AddressUtil.java | Removes parseAddress, leaving parseAndResolveAddress as the primary parser (and dropping Guava IP parsing). |
| proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java | Validates bin... |
Expected Behavior
velocity works with 26.1 Release Candidate 2
Actual Behavior
<img width="1269" height="239" alt="Image" src="https://github.com/user-attachments/assets/99ca53f9-88a9-4cc0-8b95-c2b154663578" />
velocity has support for version 26.1, but version 26.1 has not been released
yet, I decided to try version 26.1 Release Candidate 2, but it did not work.
Steps to Reproduce
1.Run velocity server
2.Add that server to multiplayer on minecraft 26.1 Release Candidate 2
3. see's this won't work
Plugin List
velocity plugins
[20:00:52 INFO]: ะะปะฐะณะธะฝั: velocity
Velocity Version
[19:58:04 INFO]: Velocity 3.5.0-SNAPSHOT (git-d11511c1-b584)
[19:58:04 INFO]: Copyright 2018-2026 Velocity Contributors. Velocity ะปะธัะตะฝะทะธัะพะฒะฐะฝะฐ ะฝะฐ ััะปะพะฒะธัั
GNU General Public License v3.
[19:58:04 INFO]: PaperMC - GitHub
Additional Information
No response
Velocity does not support the release candidate, it supports the release that will occour at tuesday
The problem with this is that disconnections caused by a duplicate login are represented in the API, specifically in the DisconnectEvent (https://jd.papermc.io/velocity/3.5.0/com/velocitypowered/api/event/connection/DisconnectEvent.LoginStatus.html#CONFLICTING_LOGIN), so by preventing the creation of the player object and its teardown, the event would not be triggered
Thatโs a fair point. I think I got a bit too focused on the internal cleanup path and not enough on the API surface.
Iโm going to move this PR back to the original ownership based fix (which keeps that behavior intact and still fixes #1740).
The problem with this is that disconnections caused by a duplicate login are represented in the API, specifically in the DisconnectEvent (https://jd.papermc.io/velocity/3.5.0/com/velocitypowered/api/event/connection/DisconnectEvent.LoginStatus.html#CONFLICTING_LOGIN), so by preventing the creation of the player object and its teardown, the event would not be triggered
The problem is now that we are already exposing the Player object to plugins through this event. Plugins can do whatever they want with the Player, including registering bossbars. Currently disconnected() only cleans up the bossbars, which could be omitted if we didn't ever expose the ConnectedPlayer object, but because we do we must consider a plugin registering bossbars on player disconnect. This sounds like weird behavior, but it's something that's possible nevertheless.
Also, it's interesting that a DisconnectEvent can be called on a player who was never connected, as far as the plugins go. Is this intentional...
There's no reason to delay setting up encryption to after we have fetched the GameProfile from Mojang.
Before this PR, this could result in a disconnect() call before we had set up encryption if Mojang's servers are down:
if (throwable != null) {
logger.error("Unable to authenticate player", throwable);
inbound.disconnect(Component.translatable("multiplayer.disconnect.authservers_down"));
return;
}
// Only here we were setting up encryption
Simulating this with throwable != null || true, we get disconnected on the client with a garbled exception message complaining about packets instead of the proper disconnect message. This is because as far as the client is concerned, encryption should already be in place.
This PR moves enabling encryption on the connection right when we receive the packet and after we're done with setting up the crypto stuff.
This whole code block is already in a giant try/catch block:
try {
// ...
} catch (GeneralSecurit```...
Expected Behavior
A clear single error-free port opening message should be displayed (just the fact that it is duplicated is wrong)
Actual Behavior
When the server starts, the output is:
[14:12:21 INFO]: Listening on /[0:0:0:0:0:0:0:0]:25565
[14:12:21 INFO]: Listening on /[0:0:0:0:0:0:0:0]:25565
[14:12:21 INFO]: Listening on /[0:0:0:0:0:0:0:0]:25565
[14:12:21 INFO]: Listening on /[0:0:0:0:0:0:0:0]:25565
[14:12:21 INFO]: Listening on /[0:0:0:0:0:0:0:0]:25565
[14:12:21 INFO]: Listening on /[0:0:0:0:0:0:0:0]:25565
[14:12:21 INFO]: Listening on /[0:0:0:0:0:0:0:0]:25565
[14:12:21 INFO]: Listening on /[0:0:0:0:0:0:0:0]:25565
[14:12:21 INFO]: Listening on /[0:0:0:0:0:0:0:0]:25565
[14:12:21 INFO]: Listening on /[0:0:0:0:0:0:0:0]:25565
When it stops, it is the same.
Steps to Reproduce
ะฃ ะผะตะฝั ััะพ ะฟะพัะฒะปัะตััั ะฟัะพััะพ ะฟัะธ ะทะฐะฟััะบะต ัะตัะฒะตัะฐ.
Plugin List
It's not about plugins. I even tried deleting the cache, libraries, and plugins folder, but it doesn't help.
Velocity Ver...
This is an effect of enabling enable-reuse-port from what I can tell
This is an effect of enabling
enable-reuse-portfrom what I can tell
I see, thanks!
I could get in after using -Dvelocity.max-known-packs=128 in Velocity, but it became ineffective after further increasing the number of mods, even after increasing the max-known-packs value again.
For anybody still interested in this, I simply wrote a plugin that transported you using the new forwarding packets to do so.
So the proxy just forwarded you to the server essentially severing the connection with the proxy itself (yes a hack, and the serve had to be exposed also in teh docker not just the proxy). Took some unique pack via PacketEvents pertaining to the modpack and used it as a key to be able to differentiate between modded and unmodded clients. This allowed me to solve my problem without a lobby, essentially it automatically determines if you're supposed to be on the modded or the unmodded server when connecting. Anything else can be built on top of this (for example I later had 3 servers, two unmodded and one modded).
I wrote it some time ago so I don't remember all the details, however in all of the months of using it, I think it worked 99.7% of the time. There were a couple of strange problems when two players joined at the same time, I personally got timed out...
I used -Dvelocity.packet-decode-logging=true to get more detailed logs and found that the Packet sent for class com.velocitypowered.proxy.protocol.packet.PluginMessagePacket was too big (expected 229378 bytes, got 1048604 bytes), so I set -Dvelocity.max-plugin-message-payload-size=2000000 and now it works.
The issue seems to have been caused by our Anti-DDoS system, sorry for the trouble!
Just translated the missing 3 lines that weren't yet
Localization is generally handled through Crowdin, see
https://papermc-io.crowdin.com/velocity
For consistency within this locale file, consider escaping the exclamation mark as \! (lines 18โ20 use escaped \!), or remove the exclamation entirely. While ! is valid in a .properties value, mixing escaped/unescaped punctuation makes the file harder to keep consistent across edits.
velocity.error.illegal-chat-characters=Illegรกlis karakterek a csevegรฉsben\!
Pull request overview
Updates the Hungarian (hu_HU) localization bundle to translate a few remaining English strings in Velocityโs proxy user-facing messages.
Changes:
- Translated
velocity.error.illegal-chat-charactersinto Hungarian. - Localized the
/sendusage placeholders (<player> <server>) into Hungarian. - Translated the proxy shutdown kick message into Hungarian.
๐ก <a href="/PaperMC/Velocity/new/dev/3.0.0?filename=.github/instructions/*.instructions.md" class="Link--inTextBlock" target="_blank" rel="noopener noreferrer">Add Copilot custom instructions</a> for smarter, more guided reviews. <a href="https://docs.github.com/en/copilot/customizing-copilot/adding-repository-custom-instructions-for-github-copilot" class="Link--inTextBlock" target="_blank" rel="noopener noreferrer">Learn how to get started</a>.
Since there were multiple PRs about adding translations IMO there should be an explicit note for how translations are handled, which seems useful in general.
Localization is generally handled through Crowdin, see https://papermc-io.crowdin.com/velocity
And escaping is only done by Crowdin and not necessary
Thanks, I didn't know that yet, I'll make sure to do it via crowdin!
Was there anything left to do on my part for this? :)
An unintentional side effect introduced as a byproduct of the additional validation added in #1743 (in particular, the check added for packet direction and connection state) is that it breaks servers running a proxy-in-proxy configuration. Granted of course this is a known grey area and this is not officially supported, however we have had numerous complaints from users claiming that after updating to Velocity for Minecraft 26.1, their server no longer works.
The aim is to keep this validation optional via an added system property, retaining support for proxy-in-proxy, as it currently works fine otherwise, without any other changes on the user-end.
If there was any specific reasoning or justification for the validation being added that I'm unaware of, please let me know, but for the most part my understanding is that it was added as a generic safeguard because this is an uncommon packet state which doesn't normally occur for a single proxy to server.
private static final boolean DIRECTION_VALIDATION = Boolean.parseBoolean(System.getProperty("velocity.packet-direction-validation", "true"));
Velocity has a utility method for this (VelocityProperties.readBoolean)
I've made the change to use VelocityProperties (no particular reason not to use this, although the existing property a few lines up used Boolean.getBoolean so I simply copied that), and set the default to true.
I would advocate for the default not being true here though, as that would mean behavior is broken by default. Still better than not having any way to configure it at all however.
@booky10 Would love your input here if the original validation was necessary to for example fix some niche issue. If it's sensitive feel free to reach out privately.
I would love to preserve this validation if it serves some purpose, but definitely need more context as to what the default should be.
The way that phase works kinda expects that we understand all of the packets used during that phase, and so not knowing stuff is a really weird situation, which can cause problems, such as not allowing a client to connect properly
The generic handling should work so this is probably not a huge concern, just, wouldn't be a setup we could provide support within
ConnectedPlayers DEFAULT_PERMISSIONS has always bothered me, because the field does not contain the default permissions of a player, it contains the default permission provider.
This PR fixes that ambiguous naming, and it also aligns VelocityConsole to a similar pattern: a single field defining the default, instead of hard-coding it multiple times in the constructor and the setupPermissions() method.
Not sure what this is trying to solve, but not resolving hostnames is pretty intentional, we expect stuff to resolve on-demand, that way people can host in mode dynamic environments without issues related to dynamically asigned IPs changing
After some more discussion, fine with keeping the default as suggested by kashike (defaulting to validation enabled). I don't have any further concerns, but let me know if the code as-is looks good or if there are any other changes code-style wise or naming wise
Ah, you're right. I have a misunderstanding.
The use case of mine is, I want to get the server ip address that the player really connected to in ServerConnection. (I can only get an unresolved one now; it may not be the connected ip if I resolve it.)
I want a feature, maybe. Something like make ServerConnection#getServerInfo() returns the actual backend ip address instead of callingRegisteredServer#getServerInfo().
This is an api enhancement of the use case mentioned in #1750. It adds a getConnectedServerInfo for getting the current connected IP and port.
If I have a backend server with some-dynamic-host-name:25565, it will be resolved in VelocityServerConnection#connect, but the resolution result (as the server player really connects to) cannot be gotten by the API; I got an unsolved InetSocketAddress instead.
It assumes future.channel().remoteAddress() will return an InetSocketAddress because it was up-cast from it in Bootstrap#connect(SocketAddress).
I hope #1764 had a detailed explanation for what I want...
Pull request overview
Adds an API to expose the resolved (actually connected) backend server address (IP/port) for a ServerConnection, addressing cases where configured ServerInfo#getAddress() may remain unresolved when a hostname is used.
Changes:
- Added
ServerConnection#getConnectedServerInfo()to expose connected/resolved server address details. - Implemented tracking of the connected serverโs resolved
ServerInfoinsideVelocityServerConnectionduring backend connect, and cleared it on disconnect.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| api/src/main/java/com/velocitypowered/api/proxy/ServerConnection.java | Adds new API method getConnectedServerInfo() for exposing the resolved/connected server info. |
| proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java | Stores connected server resolved address from Netty channel... |
Javadoc grammar/capitalization needs correction: e.g., "currently connected to" (not "current connected to") and "resolved IP" (not "ip"). Also consider clarifying that the Optional may be empty when the connection is not yet established or has been closed.
* Returns the server info that this connection is currently connected to.
* Can be used for getting the resolved IP and port.
*
* @return the server info that this connection is currently connected to, if available;
* otherwise an empty {@link Optional} if the connection has not yet been established
* or has been closed
Adding a new abstract method to this public API interface is binary-incompatible for any external implementations (e.g., tests/mocks or downstream wrappers that implement ServerConnection). Consider making this a default method (e.g., returning Optional.empty()) to preserve binary compatibility, and override it in proxy implementations that can provide the resolved address.
default Optional<ServerInfo> getConnectedServerInfo() {
return Optional.empty();
}
Expected Behavior
I encountered this issue while using the "The-Fool" modpack (forge 1.20.1)
Actual Behavior
My log:
[15:45:13 INFO]: [connected player] YGXB_net (/219.139.73.98:12335) has connected
[15:45:13 INFO]: [server connection] YGXB_net -> yz has connected
[15:45:18 ERROR]: [server connection] YGXB_net -> yz: exception encountered in com.velocitypowered.proxy.connection.backend.BackendPlaySessionHandler@7301bc5e
io.netty.handler.codec.CorruptedFrameException: Packet sent for class com.velocitypowered.proxy.protocol.packet.PluginMessagePacket was too big (expected 229378 bytes, got 432160 bytes)
at com.velocitypowered.proxy.protocol.netty.MinecraftDecoder.handleOverflow(MinecraftDecoder.java:115) ~[velocity-3.5.0-SNAPSHOT-584.jar:3.5.0-SNAPSHOT (git-d11511c1-b584)]
at com.velocitypowered.proxy.protocol.netty.MinecraftDecoder.doLengthSanityChecks(MinecraftDecoder.java:106) ~[velocity-3.5.0-SNAPSHOT-584.jar:3.5.0-SNAPSHOT (git-d11511c1-b584)]
a```...
OK, it worked. Thank you
I hope this helps others
My shell:
java -Xms1G -Xmx1G -XX:+UseG1GC -XX:G1HeapRegionSize=4M -XX:+UnlockExperimentalVMOptions -XX:+ParallelRefProcEnabled -XX:+AlwaysPreTouch -XX:MaxInlineLevel=15 -Dvelocity.max-plugin-message-payload-size=50000 -jar velocity-3.5.0-SNAPSHOT-584.jar
Expected Behavior
Plugin messages sent on registered channels during the player join process should be forwarded to the backend server via getConnectionInFlight() when getConnectedServer() is null, the same way Forge Legacy handshake messages are. Messages should not be silently discarded.
Actual Behavior
ClientPlaySessionHandler.handle(PluginMessagePacket) at lines 303 to 310 only falls back to getConnectionInFlight() when the channel is LegacyForgeConstants.FORGE_LEGACY_HANDSHAKE_CHANNEL. For all other channels, when getConnectedServer() returns null during the join window, serverConn is set to null and the handler silently skips the message. No warning, no error, no exception, etc.
VelocityServerConnection serverConn =
(player.getConnectedServer() == null
&& packet.getChannel().equals(
LegacyForgeConstants.FORGE_LEGACY_HANDSHAKE_CHANNEL))
? player.getConnectionInFlight() : player.getConnectedServer();
The null window exists between playe...
Worth noting for those looking; this also fixes some issues with Forge/Fabric servers when connecting. That in combination with velocity.max-plugin-message-payload-size fixes any connection issues that have come up with the recent commits/changes.
This is still happening.
Fixed on Velocity-CTD with https://github.com/GemstoneGG/Velocity-CTD/commit/f0bd9314fd46e860e0e3ce4daf46cb18761b41cf
The issue is that the decompression exploit happens before any packet ID + size checks down the line, because those can only be checked after the entire packet has been decompressed. Do that enough times and it's a DOS through OOM again.
Was kinda already working on compression limits due to it having been brought up elsewhere, looking at that patch looks somewhere between interesting/concerning, can't really take the code due to licensing issues, however
Was kinda already working on compression limits due to it having been brought up elsewhere, looking at that patch looks somewhere between interesting/concerning, can't really take the code due to licensing issues, however
VeloFlame forks Velocity-CTD, which forks Velocity, every fork has the GNU GENERAL PUBLIC LICENSE just like Velocity so you should be all good. Regardless, the fix on CTD is a rewritten version on the VeloFlame fix (on their end its way more comprehensive and integrated with their already existing packet guard / "firewall" features). Feel free to do with it what you want.
The fix was applied in a rush as the exploit is currently being used in the wild, any improvements/suggestions welcome of course.
Velocity-CTD has broken with Limbo* plugins. sadly, we cant use it.
Velocity-CTD has broken with Limbo* plugins. sadly, we cant use it.
offtopic but see https://github.com/Elytrium/LimboAPI/pull/243
But, its
<img width="314" height="65" alt="Image" src="https://github.com/user-attachments/assets/b777bc33-cbb6-497f-b91c-a15acc356385" />dirty fix
is the forge/fabric thing still an issue? The primary reported case this was trying to jump around was fixed by: https://github.com/PaperMC/Velocity/pull/1747
if so, would need means of reproduction
I believe otherwise this was just reported by #1723 but for our use case this is solved, so I'll go ahead and close this PR
https://github.com/PaperMC/Velocity/pull/1747 is merged now which seemed to fix some issues related to this, would be great to have this tested on other platforms by folks who were having issues
Expected Behavior
When you open a shulker inside a menu or anywhere else, the shulker should open.
Actual Behavior
When you have a shulker full of stuff inside another menu (chest-like), the proxy cuts the connection.
Here's a clip of the actual behavior: https://medal.tv/it/games/minecraft/clips/mtxNyn27yJfNu57Uh?invite=cr-MSxES00sNDk0MjAyNjU3&v=40
Steps to Reproduce
1). Open a chest or a chest-like menu (pv plugin, ...)
2). Open open the sulker
3). Try to move the shulker
Plugin List
ViaVersion v5.8.1, LuckPerms v5.4.141, Vault v1.7.3-CMI, FastAsyncWorldEdit v2.15.1-SNAPSHOT-1290+886beb5, WorldGuard v7.0.9+5934e49, PlaceholderAPI v2.12.2, ViaBackwards v5.8.1, WorldGuardExtraFlags v4.2.4-SNAPSHOT, CoreProtect v23.1, CMILib v1.5.2.4, packetevents v2.11.2, nightcore v2.6.4, HeadDatabase v4.21.2, SSManager v1.0, aura-LuckPerms v1.0-SNAPSHOT, spark v1.10.156, AdvancedEnchantments v9.22.8, BottledExp v3.2.4.0, EliteLootbox v2.4.0, Pl-Hide-Pro v2.14.3, ItemEdit v3.7.8...
Build 584 (26.1 support) was fine and we didn't encounter this issue
Can confirm I have had the issue too, had to increase the new max-compression-ratio.
what is the value that you have used? @xXkguyXx
So apparently packetevents throws an error when this thing happens but velocity doesn't even in debug mode.
what is the value that you have used? @xXkguyXx
15
I can confirm, after the changes made by @electronicboy shulkers and long nbt data causes the connection to crash for
Player has disconnected: An internal error occurred in your connection.
@xXkguyXx where did you set the max-compression-ratio
Do you have an example of an impacted item?
@electronicboy all versions, the shulker box should be full of enchanted custom items. You can contact me on discord and I can show you the exact item (Name tag: lucaf_)
Please /modmail the contents of /paper dumpitem assuming you're using a paper based backend, otherwise, I would need some means to create the item
@electronicboy
minecraft:black_shulker_box{BlockEntityTag:{Items:[{Count:1b,Slot:0b,id:"minecraft:leather_boots",tag:{Damage:0,Enchantments:[{id:"minecraft:protection",lvl:12s}],HideFlags:255,Unbreakable:1b,display:{Lore:['{"extra":[{"bold":false,"italic":false,"underlined":false,"strikethrough":false,"obfuscated":false,"color":"aqua","text":"โจ "},{"italic":false,"color":"white","text":"| "},{"italic":false,"color":"gray","text":"Protezione"},{"italic":false,"color":"white","text":": "},{"italic":false,"color":"aqua","text":"12"}],"text":""}'],Name:'{"text":"","extra":[{"text":"ั","obfuscated":false,"italic":false,"underlined":false,"strikethrough":false,"color":"#3A2A1E","bold":true},{"text":"แด","obfuscated":false,"italic":false,"underlined":false,"strikethrough":false,"color":"#392921","bold":true},{"text":"ษช","obfuscated":false,"italic":false,"underlined":false,"strikethrough":false,"color":"#382823","bold":true},{"text":"แด ","obfuscated":false,"italic":false,"underlined":false,"strike_...
Fun, I've increased the default max ratio allowed for clientbound packets, older versions/creative mode makes this fun
@electronicboy I would also suggest to add this option in the velocity.toml so the server can configure it
That is not in a location which is able to cleanly deal with accessing the configuration, we generally also don't like putting such things into the config file, ideally, people don't need to touch this stuff
These arbitrary limits really seem like a hack/plaster on the problem. There's bound to be way more issues like this, think mods sending really good compressible data. And how would the 1:64 ratio fare with a client sending a really long chat message consisting of one character?
My gut tells me theres a way better fix for these (de)compression attacks. Either detecting a client hammering hundreds of "weird"/big packets, or see if its possible to fix the actual problem where one client is allowed to generate gigabytes of decompressed packets that are queued to be processed. If we can solve that we dont need any arbitrary limits, which also deviates Velocity from the "Notchian" minecraft protocol, which mods and such are expecting.
Side note, how does vanilla MC / paper deal with this? It seems like these type of attacks are targeting Velocity itself, and the backends aren't really affected.
We have 0 context of "weird", that's the problem; the backends have less to worry about because they actually understand the context of the data and are able to apply natural limits to the data being passed as a result of that, your 8MB packet is seen as invalid and so you get booted from the network and your buffer cleaned out quickly
netty has a backpressure system, but it's not really good for the cases where the explosion happens in the pipeline rather than out of it, we could maybe emulate something like it to limit the damage done, however
We have 0 context of "weird", that's the problem; the backends have less to worry about because they actually understand the context of the data and are able to apply natural limits to the data being passed as a result of that, your 8MB packet is seen as invalid and so you get booted from the network and your buffer cleaned out quickly
netty has a backpressure system, but it's not really good for the cases where the explosion happens in the pipeline rather than out of it, we could maybe emulate something like it to limit the damage done, however
Something to think about. I have no doubt the limits in place will relieve most attacks, but as we've already seen a lot of people need to increase the limits. Especially modded networks, leaving them vulnerable in particular. Imo a fix that leaves a portion of the userbase vulnerable is not a fix at all, but I appreciate how quickly this was implemented and it patching probably >90% of Velocity instances.
Though I do wonder if a "wind...
Can someone explain why does this attack work in the first place?
I do not understand where leak happens.
In my head packet flow is this:
read():
MinecraftCompressDecoder#decode
creates new ByteBuf (8 mb) refCnt() == 1 ->
MinecraftDecoder#channelRead: did nothing, refCnt() == 1 ->
MinecraftConnection#channelRead
BackendPlaySessionHandler#handleUnknown ->
backendChannel.write(buf.retain()), refCnt() == 2
//We still in same eventLoop(), context switch does not happen. ByteBuf immidialty goes throught Pipeline
MinecraftCompressorAndLengthEncoder(MessageToByteEncoder)#write -> buf.release(), refCnt == 1
finally block:
buf.release(), refCnt == 0
refCnt reaches 0 -> netty should release memory, and next reads should reuse it
repeat read()
repeat read()
repeat read()
I dont see where memory leaking could happen.
- Does channel#write, somehow can still do context switch even we already ins...
UPD:
Looks like i found the issue:
MinecraftCompressorAndLengthEncoder allocates 8mb + some bytes for headers ByteBuf.
https://github.com/PaperMC/Velocity/blob/e834af9cf10d6c13703cb9ff6f349e196cb3d2bd/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressorAndLengthEncoder.java#L92
then netty's ChannelOutboundBuffer will store that entire ByteBuf until flush() called.
And this is where leak happens.
https://github.com/PaperMC/Velocity/blob/dev/3.0.0/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java#L468
Probably you can manually calculate here how many bytes proximititly are gonna allocated by this write and do force flush if it more then XX mb are queues (one write will be always buf.readablyBytes() + some bytes)
1a41b77 Add 26.1.2 version string to 26.1 protocol version... - RealBauHD
I would note that "leak" generally has a pretty strong meaning, "memory sits around until flushed" is not a leak; But, that would in restospect explain some stuff, that isn't handled on the flush but on the channel readComplete, which apparently the newer adoptive allocator makes even worse?
I'm still somewhat inclined to keep some of the other checks just due to the nature, but can probably back off them; limiting how much can sit in the chain is something I was already trying to look into how to handle cleanly
limiting how much can sit in the chain is something I was already trying to look into how to handle cleanly
I think compression encoder can simply calculate how many bytes it allocated and if too many then do flush().
Something like this:
private int threshold;
private final VelocityCompressor compressor;
+ private long allocatedBytes = 0;
public MinecraftCompressorAndLengthEncoder(int threshold, VelocityCompressor compressor) {
this.threshold = threshold;
@@ -51,6 +52,16 @@
} else {
handleCompressed(ctx, msg, out);
}
+ allocatedBytes += out.capacity();
+ if (allocatedBytes >= 64MB) {
+ ctx.channel().flush();
+ }
+ }
+
+ @Override
+ public void flush(ChannelHandlerContext ctx) throws Exception {
+ allocatedBytes = 0;
+ super.flush(ctx);
}
private void handleCompressed(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out)
If no compression, then backpressure should help to mitigate
I think the solution here might be to just get rid of this optimisation
Maybe just reduce to something like 10 packets before flush for proxy -> backend? With 2MB limit it will be only up to ~20MB stored.
am I wrong in thinking that this is backwards? The concern here is what clients are sending the server, not the inverse, but that's only dealing with S > C packets, and the batching there is generally fine, worse case I figure we can probably just do a force flush if we know the packet is is over some size
My understanding is that the exploits we're trying to patch is purely C > S, which is the other way around.
as an aside, with the new adoptive allocator, I wonder if it makes sense to get rid of the compression presizing, at least for natives, it seems that the thing already handles that just fine and worse case we'd see a single resize without any of the fuss, at least for the max cacacity, the java one is more of a concern but maybe worth just taking the hit, most packets compress down fairly well in the first place, so we're often in worse compression cases seeing 1/4 of the buffer be overheads, and that's without the pooling being accounted
proxy -> backend means this https://github.com/PaperMC/Velocity/blob/dev/3.0.0/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java#L468 where packet from client is forwarded to backend.
Client -> proxy -> backend
Backend -> proxy -> client
batching proxy to client is fine with current force flush limit, but proxy to backend force flush limit seems very high, client do not seens that many packets anyway. 15-20 packets before flush seems good value.
that's a packet being sent from the backend to the client
Oops, my bad, didnt notice i am inside wrong handler.
Then i again do not understand what causing OOM.
If you have access to that exploit, can you try with Pooled allocalor?
Expected Behavior
player does not gets kicked
Actual Behavior
player gets kiked.
Steps to Reproduce
use axiom through a velocity proxy. Do a big change, player gets kiked.
Plugin List
none
Velocity Version
3.5.0-SNAPSHOT #590
currently latest
Additional Information
com.velocitypowered.proxy.protocol.packet.PluginMessagePacket was too big
[19:04:25 INFO]: [connected player] xXJuliGameXxf (/127.0.0.1:60903) has disconnected: An internal error occurred in your connection.
[19:04:25 INFO]: Exception while handling plugin message packet for [connected player] xXJuliGameXxf (/127.0.0.1:60903)
io.netty.handler.codec.CorruptedFrameException: Packet sent for class com.velocitypowered.proxy.protocol.packet.PluginMessagePacket was too big (expected 229378 bytes, got 488758 bytes)
at com.velocitypowered.proxy.protocol.netty.MinecraftDecoder.handleOverflow(MinecraftDecoder.java:115) ~[server.jar:3.5.0-SNAPSHOT (git-1a41b77c-b590)]
at com.velocit```...
Let's continue this discussion in a new/relevant issue. I already had an issue open for this for a little while: https://github.com/PaperMC/Velocity/issues/1742
If someone with maintainer rights can get rid of the offtopic comments on there that'd be useful.
This is not stale. It is a real issue that is hard to track down, and it has affected multiple users.
Over the course of 2 years or so, 6 users have reported this problem to me.
This is not a matter of plugins or no plugins. A plugin that merely registers a command shouldn't cause players to be disconnected.
A potential lead
I received the first report of this bug in July 2024. A user was having trouble on Velocity build #402.
They performed their own debugging, and as soon as they downgraded to build #400, the problems stopped.
The user concluded that code changes surrounding commands with signable component caused this error. Due to a lack of communication neither of us filed a bug report, but this bug surfaced rarely and has been a shadowy menace since. It seems to be the product of nondeterministic factors as I can never reproduce it, but it comes back repeatedly to haunt users of my plugin (LibertyBans) which registers the /ban command.
Logs
Today I obtained logs from a user...
Introduces CustomArgumentType interface which wraps native Brigadier argument types allowing for the creation of custom arguments.
Sends the native type to the client while parsing into the custom type.
Users create the argument node with the standard RequiredArgumentBuilder. Only when velocity wraps the arguments are they converted into the actual CustomArgumentCommandType.
Implemented nearly identically to Paper's CustomArgumentType.
We can't process cancelling signed chat messages and such on the proxy without entering illegal state territory in which your user would be disconnected the next time they send a signed chat/message to the server; This is generally not considered a bug and is sadly a limitation of the MC protocol, the only way to get around this right now would be using a plugin like signed velocity, otherwise, we would need some means of handshaking with the server to be able to aknowledge what has happened
Oh, I understand that. My question is though, why isn't it reproducible?
I suspect something more complicated is going on here. This is the error message; please take a look, as these are not signed chat messages we're talking about. I can't reproduce it, but other users have -- even with no other plugins installed.
[22:55:15 INFO]: [server connection] Blue_Gamer48 -> lobby has connected
[22:55:31 FATAL]: A plugin tried to deny a command with signable component(s). This is not supported. Disconnecting player Blue_Gamer48. Command packet: SessionPlayerCommand{command='ban Blue_Gamer48 Test', timeStamp=2026-04-11T20:55:31.326Z, salt=-1618365530119402377, argumentSignatures=ArgumentSignatures{entries=[ArgumentSignature{name='reason'}]}, lastSeenMessages=LastSeenMessages{offset=0, acknowledged={}, checksum=1}}
[22:55:31 INFO]: [connected player] Blue_Gamer48 (/188.108.208.192:60113) has disconnected: A proxy plugin caused an illegal protocol state. Contact your network administrator.
[22:```...
Is this log coming from SessionCommandHandler or KeyedCommandHandler? Unfortunately both classes share the logger instance of their interface, CommandHandler, which is not ideal. Would probably good to fix this, also.
I can provide more details privately if needed
SessionPlayerCommandPacket. You can tell because SessionPlayerCommand{...} is the toString() output for the packet.
I just checked the code, and there are 5 code paths generating a similar message. Although it doesn't affect this issue, I submitted a PR to clarify the 2 of 5 that were ambiguous: #1773
[PaperMC/Velocity] New branch created: update/adventure/5.0.0
0f905bb Update to Adventure 5.0.1 - 4drian3d
Make it easier for users to provide us the full version string when asked to in support channels, if they're running the command in game instead of in console.
This PR introduces several high-performance features and security enhancements to Velocity, specifically optimized for high-traffic networks.
Key Enhancements:
- Advanced Packet Limiter: Adds a type-aware packet rate limiter (Chat, TabComplete, PluginMessages) to prevent common exploits and CPU exhaustion.
- MSPT-based Load Balancing: Introduces a
ServerHealthTrackerthat monitors backend MSPT. Players are now dynamically routed to the healthiest server instead of simple round-robin. - Global Profile Cache: Integrated a Caffeine-based cache for GameProfiles to reduce Mojang API hits and decrease login times.
- Performance First: All implementations follow Velocity's strict coding standards and utilize high-performance native-friendly logic.
These additions make this fork a powerhouse for networks requiring extreme stability and security.
AI Slop
I didn't know servers write MSPT in the MOTD ๐ง
Thanks for the feedback. The logic for reading MSPT data from the MOTD was initially added as a rapid prototype (PoC) solution for networks already utilizing specific telemetry plugins (like ServerListPlus, etc.). Naturally, in a production environment, synchronizing this data via an external telemetry layer like Plugin Messaging or Prometheus is much more robust. The codebase is designed to be modular enough to ingest this data from various sources. Rather than labeling a prototype feature as 'slop,' I would prefer to discuss the architectural merits. I've revised this section in the latest commit to be more modular.
This is a nightmare. Caching GameProfiles returned by Mojang's hasJoined URL removes any online-mode checks and lets any offline player join as an online mode player, as long as an online mode player had joined before (priming the cache).
AI Slop
It truely is, noone with proper knowledge would produce such a PR. This is not meant as an insult, but please do some actual learning in this field instead of PR-farming with slop if you're interested in this!
Velocity already has a partial packet limiter and these sensitive matters are mostly handled by maintainers or long time contributors for various reasons.
Also adding modules that depend on things outside the Vanilla protocol are AFAIK not really wanted.
And sorry but it doesn't look like "you" revised anything here. And even then most features are questionable at best and for example caching the game profiles like this is dangerous.
This is not an issue with this PR per-se, but there are no migrations in place for messages.properties or any similar file for a different languages. Updating velocity without removing messages.properties or manually adding this key will make the hover text show up as the translation key. Is this something that should be considered in the future? Message files migrations for adding keys, just like there's a migration system in-place for velocity.toml?
would a
private String getCopyableVersionString() {
return version.getName() + " " + version.getVersion();
}
be more maintainable here?
It would probably make more sense to keep CommandHandler an interface and give each implementing class it's own logger field (though that being said this class does contain a suspiciously large amount of default implemented methods). As the log messages are exactly the same, it would be helpful to see which class is logging the messages.
No external project is expected to implement this method other than the velocity-proxy artifact...
Why does Set<BossBar> bossBars need to be monotonically non-null? Seems like no real performance gain for less readability.
public @UnmodifiableView @NonNull Iterable<? extends BossBar> activeBossBars() {
org.checkerframework.checker.nullness.qual.NonNull is imported
Why does
Set<BossBar> bossBarsneed to be monotonically non-null? Seems like no real performance gain for less readability.
What are you talking about?
For me at least it is Nullable:
https://github.com/PaperMC/Velocity/pull/1756/changes#diff-1cd097c1de92fff8c43bc33eb4f52405eb5396f9e8cc922a4502e4cad12e1f88R189
Why does
Set<BossBar> bossBarsneed to be monotonically non-null? Seems like no real performance gain for less readability.What are you talking about? For me at least it is Nullable: https://github.com/PaperMC/Velocity/pull/1756/changes#diff-1cd097c1de92fff8c43bc33eb4f52405eb5396f9e8cc922a4502e4cad12e1f88R189
yes but you're treating it as a monotonically non-null value. we can just leave it as a
private final Set<BossBar> bossBars = new HashSet<>();
and omit any null checks down the line. keeping this value null until it's used doesn't seem like it'll affect performance at all, and it makes the code that's using this field less readable (null -> either instantiate this set when modifying it, or assuming an empty set when querying it)
They don't though (https://github.com/PaperMC/Velocity/pull/1756/changes#diff-1cd097c1de92fff8c43bc33eb4f52405eb5396f9e8cc922a4502e4cad12e1f88R613), or am I missing something?
oh yes my bad, its not monotonically non-null, but my point still holds. this can be a HashSet that's initiated once (at construct time of the object) and only updated/queried without null-checks. that'd get rid of null-checks in every method that's using this field
Could you explain more where you think this method should be added? I don't really see how this would improve maintainability.
This is not an issue with this PR per-se, but there are no migrations in place for
messages.propertiesor any similar file for a different languages. Updating velocity without removingmessages.propertiesor manually adding this key will make the hover text show up as the translation key. Is this something that should be considered in the future? Message files migrations for adding keys, just like there's a migration system in-place forvelocity.toml?
This problem also came to my attention when working on this pr. However, solving it is way out of scope of this pr and should be discussed in a separate issue.
When reuse-port is enabled in the config, the listening on and closing endpoint messages are logged for every endpoint that is opened/closed, even when as far as I can tell, the address being logged is always the same
Fixes #1755
Maybe a good opportunity to log on how many endpoints we are listening/closing on? Or is that too verbose?
I 50/50 considered mentioning that in the pr description, but wasn't sure how useful it is to know the number of open endpoints
I 50/50 considered mentioning that in the pr description, but wasn't sure how useful it is to know the number of open endpoints
That is something that's lost with this PR. It's cumbersome but you would be able to count the number of logs for this. Maybe only log the number if it's > 1?
In the same VelocityCommand.Info record, right above or below run().
As to why this should (could) be a separate helper method, it's not run()'s responsibility to format this string. Having it be a separate method is clearer and easier to find/modify at a later date.
Though that makes me think, maybe this better as a translatable message in messages.properties? That way this would be a Component.translatable() call with two arguments (name + version) and it's the translatable component responsibility to format this properly.
Expected Behavior
I have a server bundle on the ArcLight core. When I add the Create Aeronautics and Sable mod, I can't connect. Everything works without the mod.
Actual Behavior
[12:57:52 INFO]: Booting up Velocity 3.5.0-SNAPSHOT (git-f712997d-b593)...
[12:57:52 INFO]: Connections will use NIO channels, Java compression, Java ciphers
[12:57:52 WARN]: The proxy is running in offline mode! This is a security risk and you will NOT receive any support!
[12:57:52 INFO]: Loading localizations...
[12:57:52 INFO]: Loading plugins...
[12:57:52 INFO]: Loaded plugin cmiv 1.0.1.2 by Zrips
[12:57:52 INFO]: Loaded plugin minimotd-velocity 2.1.3 by jmp
[12:57:52 INFO]: Loaded 3 plugins
[12:57:52 INFO] [cmiv]: Registering event listeners
[12:57:52 INFO]: Listening on /[0:0:0:0:0:0:0:0]:38745
[12:57:52 INFO]: Done (0,75s)!
[12:57:53 INFO] [minimotd-velocity]: There is an update available for MiniMOTD!
[12:57:53 INFO] [minimotd-velocity]: This server is running version v2.1.3, which is 9 ver...
The mod uses a custom argument type which is not something velocity can understand, you would need to see if there is a mod for the platform you use which supports wrapping command arguments a la crossstitch
When reuse-port is enabled in the config, the listening on and closing endpoint messages are logged for every endpoint that is opened/closed, even when as far as I can tell, the address being logged is always the same
Fixes #1755
I remember creating a similar issue report and assume this might actually be intentional when digging deeper into logs: https://github.com/PaperMC/Velocity/pull/1535#issuecomment-2753979167
Maybe this should be reapproached?
As to why this should (could) be a separate helper method, it's not run()'s responsibility to format this string. Having it be a separate method is clearer and easier to find/modify at a later date.
Thanks for your input, however, I don't think this really matters that much, so I'm gonna leave this as-is for now.
Though that makes me think, maybe this better as a translatable message in messages.properties?
As to making this message translatable, this doesn't make a lot of sense in my opinion. The translation string would essentially be `{0} {1}, so I think this is also fine as-is.
Deprecates ServerInfo#getAddress and errors if it is a unix domain socket, current velocity proxies setups should remain working.
Adds a new method ServerInfo#getSocketAddress as alternative.
Based on https://github.com/PaperMC/Velocity/pull/991, https://github.com/PaperMC/Velocity/pull/422, https://github.com/PaperMC/Velocity/commit/b00389029f4c11ad34898b5298625f4fcfc03de5, https://github.com/PaperMC/Velocity/commit/b00389029f4c11ad34898b5298625f4fcfc03de5
At higher playercounts a lot of player tablist packets can be sent concurrently causing some small thread congestion (across all netty threads). This is a small optimization to prevent this congestion by just generating the uuids using threadlocal random.
invalid UUIDs is generally a no-go in my book, using a non-secure random also introduces some risks around duplicate UUIDs being generated
invalid UUIDs is generally a no-go in my book, using a non-secure random also introduces some risks around duplicate UUIDs being generated
Changed to a valid uuid v4, I don't think the duplicate uuid is a real issue as there are so many random bits I don't think it will ever collide
Have you measured the performance of java's random UUID generation and this proprietary implementation? Is it even worth it to roll our own, aside from possibly security/duplicate UUID concerns?
Have you measured the performance of java's random UUID generation and this proprietary implementation? Is it even worth it to roll our own, aside from possible security/duplicate UUID concerns?
Yes at higher player counts there is thread congestion on netty threads (this worsens with the higher the threads and all players getting the same player info packets at the same time)
The security UUID concern should not be applicable here as they are only used as identifiers internally.
I kept the UUID.randomUUID() in click callbacks to ensure the security.
Also, how "unique" do the UUIDs have to be in the tablist? Could we increment the lower or higher long to keep the UUIDs "locally" unique per session or per tablist? That would speed this up a lot. Kind of similar how anonymous player entries in the server player list packets are expected to have a uuid of new UUID(0, 0).
Also, how "unique" do the UUIDs have to be in the tablist? Could we increment the lower or higher long to keep the UUIDs "locally" unique per session or per tablist? That would speed this up a lot. Kind of similar how anonymous player entries in the server player list packets are expected to have a uuid of
new UUID(0, 0). Though that does abuse the hell out of the universally unique IDs here.
This should technically also work for the legacy tablist implementations. The uuid is used to have a unique id for a player name as UUIDs aren't send in legacy with the tablist packets.
https://github.com/f4b6a3/uuid-creator
UUID Version 7: the Unix Epoch time-based UUID specified in RFC 9562.
Would be a perfect fit here.
https://github.com/f4b6a3/uuid-creator
UUID Version 7: the Unix Epoch time-based UUID specified in RFC 9562.
Would be a perfect fit here (
UuidCreator#getTimeOrderedWithRandom/UuidCreator#getTimeOrderedEpoch[Fast]).
Is it really needed? The current implementation keeps the v4 validity and the probability of actually having a collision is astronomically low.
I think relying on an external library for this rather than manually fiddling with bits in our own FastRandomUuid is favorable. Its current name also suggests its perfectly safe to use in other cases where a random uuid is needed, which its really not due to relying on a non-secure random generator.
I think a better solution would be to get rid of this class and move it to VelocityTabListLegacy as a private static method (does the bossbar class actually re-generate the random uuids a bunch of time?)
I think relying on an external library for this rather than manually fiddling with bits in our own FastRandomUuid is favorable. Its current name also suggests its perfectly safe to use in other cases where a random uuid is needed, which its really not due to relying on a non-secure random generator.
I think a better solution would be to get rid of this class and move it to VelocityTabListLegacy as a private static method (does the bossbar class actually re-generate the random uuids a bunch of time?)
The method is now only present in VelocityTabListLegacy. I don't think an additional library is really needed, the collision chances are basically zero and the uuid is structurally valid. It's also not a usable "uuid" as it's used to spoof a tablist entry for temporary binding to a tab name.
The bug is still occurring in version 26.1.2
We get the error: โkeepalive: time out (out of order!)โ
Several disconnections a day for various players.
I'm not entirely sure whether it's an โout of orderโ error with keepalive packets or with the chat specifically. The strange thing is that you don't even need to type commands or send messages in the chat; just exploring the world for a few minutes is enough to trigger this โtimeoutโ error.
The bug is still occurring in version 26.1.2 We get the error: โkeepalive: time out (out of order!)โ Several disconnections a day for various players.
I'm not entirely sure whether it's an โout of orderโ error with keepalive packets or with the chat specifically. The strange thing is that you don't even need to type commands or send messages in the chat; just exploring the world for a few minutes is enough to trigger this โtimeoutโ error.
Can you send a screenshot of this error?
Fix chat race conditions not addressed by #1042.
Despite #1042 serializing chat/command processing through ChatQueue, two issues allowed out-of-order packets to reach the backend:
- Rate-limited commands bypassed
ChatQueueentirely
RateLimitedCommandHandler returned false when a command was rate-limited and forward-commands-if-rate-limited was enabled (the default). This caused the Netty dispatch path to write the packet directly to the backend via handleGeneric, racing ahead of any earlier commands still waiting in the queue for their CommandExecuteEvent to complete. Under rapid command bursts (e.g. litematica's schematic paste), this produced the exact out_of_order_chat kick described in #1042.
Fix: route rate-limited commands through ChatQueue via a new forwardRateLimited path, skipping plugin event firing but preserving write order.
ChatQueue.writePacketblocked the Netty event loop
writePacket submitted a runnable to the event loop that called awaitUninterrupti...
@7wOv6ySCjo could you check and confirm whether #1782 solves this issue for you or not?
Just so you're aware there are other PR's such as #1655 that implement a per-server forwarding mode, which IMO is preferable.
Also adding util methods to the enum would probably make it more readable
VelocityRegisteredServer line 103-109 seems very fishy. It's converting one enum class to another, both with exactly the same value set.
I would consider moving the PlayerInfoForwarding class to the api module instead and use that everywhere instead.
There is a PR to expose the forwarding mode that wasn't merged since it's deemed more of an internal property
Though when making the decision that exposing this through the api module is undesired, I think it would be better to make ServerInfo an interface and implement it in the proxy module with the additional PlayerInfoForwarding field. I'm pretty sure that would break binary compatibility with plugins though... If that's something that we should be concerned about, extending this class as class VelocityServerInfo extends ServerInfo with the additional property would probably be best here. I just really dislike having two identical enums, one in the implementation module and one in the api module, and converting between the t...
The bug is still occurring in version 26.1.2 We get the error: โkeepalive: time out (out of order!)โ Several disconnections a day for various players.
I'm not entirely sure whether it's an โout of orderโ error with keepalive packets or with the chat specifically. The strange thing is that you don't even need to type commands or send messages in the chat; just exploring the world for a few minutes is enough to trigger this โtimeoutโ error.Can you send a screenshot of this error?
<img width="1458" height="183" alt="Captura de pantalla (8136)" src="https://github.com/user-attachments/assets/bd32f6a7-f6f7-43c6-bdad-798b41c8fc77" />
This usually happens with entity ID number 1, as it doesnโt happen as often with subsequent entities ID, but it still disconnects the user.
I investigated the code and the line causing the disconnection is in: net.minecraft.server.network.ServerCommonPacketListenerImpl
LOGGER.info("Disconnecting {} for sending keepali...
-
Remove restrictive handshake hostname length limit: The 261-character
MAXIMUM_HOSTNAME_LENGTHinHandshakePacket.decode()silently disconnects clients when enough plugins inject forwarding data into the hostname field that the combined length exceeds the limit.readString(buf)now uses the default 65536 limit, matching every other string field and aligning with Paper/Spigot's equivalent fix (readUtf(255)toreadUtf(Short.MAX_VALUE)inClientIntentionPacket). -
Fix plugin messages silently dropped during player join: Fixes #1766
Can this issue be re-opened? I have provided significant documentation and leads.
This is not about signed chat messages, but rather simple registration of unsigned commands.
When will be merged?
When will be merged?
Personally, I'm waiting for more plugins to update to Adventure 5 on their own, since there are changes that break compatibility with existing plugins, some of which need to be recompiled to work with the new version, while others require a compatibility layer to work with both versions (Adventure 4 and 5)
I think that they're looking to address the ABI breakage
Most likely a copy/pasta mistake; the exception(Throwable) method gets called in many more cases than just bad plugin messages.
ad8de43 Fix wrong logs in exception(Throwable) (#1784) - WouterGritter
While working through implementing Legacy+BungeeGuard forwarding for ProxyCompatibleForge, I realized that #1176 never implemented a way for Velocity to forward the modern FORGE[#] hostname token when legacy forwarding types were in use.
Additionally, while testing I found that the existing token forwarding for 1.8 - 1.12.2 didn't work with BungeeGuard forwarding.
The latter was a simple one-line fix, but I'd like some feedback regarding forwarding the modern FORGE[#] token, or if there are any other sections that need a tidy.
Somewhat in-line with Waterfall's "forgeClient" and "extraData" properties, I've added a new "modernForgeClient" property to account for backend implementations that always associate "forgeClient" with the older FML token, or backend implementations built with respect to Waterfall assuming the forwarded token is in the form of FML[#]. Any implementation that appends the "extraData" verbatim to the hostname (and replaces \1 with \0) should continue to funct...
Haven't had the chance to tidy things up yet (the fork linked above works but isn't configurable), but there's already an open draft PR for this (#1700).
Whoops, wasn't aware renaming the branch wasn't GitHub-wide
Here's the current state of things:
Config setting: advanced.modern-forwarding-allow-legacy-connections
System Property: velocity.register-login-plugin-messages-for-legacy-versions
Given the two will most often be used in tandem I wonder if it'll be better to have them both as system properties, as that would also cut down on the chances of a casual user accidentally enabling the advanced setting and getting an odd connection error.
I'm also open to new name ideas, as that property name is abysmally long.
Generally people update when the platform that implements it updates, so for us we're going to revert the update to Adventure 5.0 until Velocity updates
The packets-per-second limit was introduced to mitigate compression bomb attacks, where an attacker floods the proxy with small packets that decompress to the maximum allowed size. It's the wrong metric for this, though: 500 packets/s at 2 MiB each is 1 GiB/s of decompressed data, which kills the proxy just as effectively. At the same time, legitimate clients with chatty mods (e.g. heavy plugin-message traffic) were getting disconnected despite consuming far less than any attacker would.
This PR adds a decompressed-bytes-per-second limit to [packet-limiter], applied after decompression in MinecraftCompressDecoder. This directly measures what was causing OOM issues, rather than using a proxy metric. With a default of 5 MiB/s over a 7-second window (35 MiB of headroom per window), legitimate clients should never get close to this limit, while any compression bomb is caught well before it causes memory pressure.
Default changes (config version 2.7 -> 2.8):
packets-per-second: 500...
I wonder what your usecase for this feature is? I think the 'modern' go-to solution for a sort of 'anonymous'/intermediate proxy not exposed to the world would be to use Docker and Docker's networking.
I wonder what your usecase for this feature is? I think the 'modern' go-to solution for a sort of 'anonymous'/intermediate proxy not exposed to the world would be to use Docker and Docker's networking.
Using Docker still allows using Unix Domain Sockets, and the performance will be (slightly) better most likely.
I wonder what your usecase for this feature is? I think the 'modern' go-to solution for a sort of 'anonymous'/intermediate proxy not exposed to the world would be to use Docker and Docker's networking.
I think most people would use this for better performance when having multiple servers on the same machine. As you said there are different (or even better) alternatives for networking security.
[PaperMC/Velocity] New branch created: cat/initial-choose-server-resulted
aa9e02d Convert PlayerChooseInitialServerEvent into a resu... - electronicboy
https://github.com/PaperMC/Velocity/pull/1787 - saw somebody reference this, is maybe more inlined with a better pattern for this sorta thing
//noinspection UnnecessaryReturnStatement
return;
Seems unnecessary? I don't see why you would want a return here?
Maybe one of those fancy new switch "instanceof" statements would be better here anyway (JEP 441), throwing on default (unknown/unexpected result type)
I'd originally wrote this without the else statement and then remembered I needed it so I could for the if anyways. I do know that IJ itself tended to get upset with shorter case switches and so I did tend to avoid them for stuff like this
Inconsistent formatting (no whitespace after class declaration, Allowed does have this)
Is it an idea to force this with checkstyle? Whitespace after class declaration, or newline checking in general, idk if we currently have this. Iirc this is quite inconsistent in the codebase
Fair enough, still I think line 270 and 271 can be deleted
Yea, we don't really have a hard rule on this and it's pretty easy to miss when refactoring during working on something, need to update checkstyle and formalise rules for this stuff
readByteArray already takes a cap and rejects oversized counts, but readKeyArray, readIntegerArray, readStringArray and readVarIntArray only check that the count fits in the remaining buffer bytes. Since each entry is 4 to 8 bytes (a primitive int or an Object reference) but the buffer check is in bytes, a single varint count of around the frame size lets a peer push us into a 4x to 8x larger heap allocation than the wire bytes.
For example readIntegerArray was reachable from AvailableCommandsPacket (clientbound). Setting the array length to ~2M passes the isReadable(length) check and we then new int[~2M], an 8 MiB allocation per packet. Similar story for the other three.
Adds a cap parameter to each of the four readers, defaults to DEFAULT_MAX_STRING_SIZE (the same constant readByteArray uses) and rejects with the existing checkFrame if the count exceeds it. Tests for the cap path are added.
./gradlew :velocity-proxy:test :velocity-proxy:checkstyleMain clean.
Problem
Fuzzing found two reproducible decode-time crashes:
- NegativeArraySizeException in ProtocolUtils.readBinaryTag(...) (bubbles up from Adventure NBT parsing).
- JsonSyntaxException/MalformedJsonException in LegacyPlayerListItemPacket.readOptionalComponent(...).
These exceptions were unhandled and could crash/abort decode paths instead of failing gracefully.
[PaperMC/Velocity] New comment on pull request: #1788 Cap array allocations in ProtocolUtils readers
Restricting these from strictly server-defined data is not a really concern
[PaperMC/Velocity] New comment on pull request: #1788 Cap array allocations in ProtocolUtils readers
Fair on the single-backend case. I was thinking more about proxies fronting multiple backends, where one bad backend shouldn't be able to take out players connected to the others. If you don't see value there, happy to close this. Otherwise I can rework it as an opt-in system property (like velocity.max-known-packs) so default behavior is unchanged.
Expected Behavior
it must start!!
Actual Behavior
Latest version replaces .jar file with new version and can then not access that file itself. It worked until I replaced the docker image today.
Here the log messages:
2026/05/11 14:12:08,stdout,Error: Unable to access jarfile ./velocity-3.5.0-SNAPSHOT-595.jar
2026/05/11 14:12:08,stdout,[init] Setting initial memory to 2048m and max to 2048m
2026/05/11 14:12:07,stdout,[init] Replacing env variables in configs that match the prefix CFG_...
2026/05/11 14:12:07,stdout,[0;39m[init] /server/forwarding.secret already exists
2026/05/11 14:12:07,stdout,[39m[mc-image-helper] 12:12:07.019 INFO : The file /server/velocity.toml already exists
2026/05/11 14:12:04,stdout,"[0;39m[init] Downloading default top-level configs, if needed
"
2026/05/11 14:12:04,stdout,[0;39m[39m[mc-image-helper] 12:12:04.231 INFO : Removing old file velocity-3.5.0-SNAPSHOT-594.jar
2026/05/11 14:12:04,stdout,[39m[mc-image-helper] 12:12:04.221 INFO : Do...
We have zero control over how your docker image downloads and bootstraps the jar
I think returning -1 in HandshakePacket#decodeExpectedMaxLength isn't desirable. No authentication is required to send this packet, anyone can open TCP connections & spam this packet possibly opening up DOS attacks again that were mitigated by some recent commits.
I think returning -1 in
HandshakePacket#decodeExpectedMaxLengthisn't desirable. No authentication is required to send this packet, anyone can open TCP connections & spam this packet possibly opening up DOS attacks again that were mitigated by some recent commits.
Good point. I was assuming the VarInt limit handled it, but 2MB is obviously still an exploitable size. The hostname is now capped at Short.MAX_VALUE characters, which matches Paper's readUtf(Short.MAX_VALUE) in ClientIntentionPacket.
See https://github.com/GemstoneGG/Velocity-CTD/pull/885
Is is true that this PR adds support for https://github.com/SendableMetatype/EduGeyser? Is there any other reason why this PR is needed?
These fixes have nothing strictly to do with EduGeyser support. They fix general Velocity bugs that any plugin setup can trigger under the right conditions. I just happened to run into them and bother diagnosing them.
I mean, this looks like two distinct set of changes
-
The plugin message thing, this would be a bug
-
the hostname length limit, this isn't a bug fix, at least not as we consider it given that we cater to the vanilla protocol, increasing it beyond the vanilla length limit on the incoming side is pretty breaky behaviorally
See GemstoneGG#885
Is is true that this PR adds support for SendableMetatype/EduGeyser? Is there any other reason why this PR is needed?
Just cloning into velocity ctd before velocity, i fixed the title too to fix the misleading stuff
increasing it beyond the vanilla length limit on the incoming side is pretty breaky behaviorally
I'd consider putting it behind a system property, with vanilla defaults. That could at least give the user the option to have support for things like EduGeyser, just like we have with many other limits.
I mean, this looks like two distinct set of changes
- The plugin message thing, this would be a bug
- the hostname length limit, this isn't a bug fix, at least not as we consider it given that we cater to the vanilla protocol, increasing it beyond the vanilla length limit on the incoming side is pretty breaky behaviorally
Regarding the hostname limit: Paper/Spigot made the equivalent change years ago (readUtf(255) to readUtf(Short.MAX_VALUE) in ClientIntentionPacket) for the same reason - plugins inject forwarding data into the hostname field, which is standard practice in the BungeeCord forwarding model. Velocity's own encode() already writes hostnames with no length cap, so the decode side is just being made consistent. The limit is now Short.MAX_VALUE to match Paper, and decodeExpectedMaxLength is kept in place for DoS protection on the unauthenticated packet.
Spigot made that change year ago purely for their forwarding mechanism and nothing else, it breaks compatability with the vanilla protocol in a way which prevents the proxy from being able to connect to vanilla servers entirely. The decode/encode inconsistency here is just a sad reality of how that mechanism is intended to work to keep compat with legacy forwarding.
That data inside of that packet is somewhat trusted due to the vanilla protocol limit on the decode side usually getting in the way of doing anything fancy there, effectively removing that limit stands out as a potential security risk at the very least; it's definetly not something I feel should just be changed overnight
There are a couple issues with this PR:
-
This vulnerability can be exploited by a DoS attack and this fix will improve code robustness
This path is not exploitable client-side. Both cases where the exceptions are caught are clientbound-only. This could only be exploited by a malicious backend server.
-
readBinaryTag()can throw way more than just theNegativeArraySizeException(most obvious example is a bad array index in ProtocolUtils#readBinaryTag line 506;BINARY_TAG_TYPES[buf.readByte()]) -
The server won't crash anyways as the uncaught exceptions will be caught upstream (
MinecraftDecoder#tryDecode)
The incoming decode limit doesn't affect vanilla backend compatibility. Velocity controls what it sends to backends based on forwarding mode, and the encode side already has no length cap, so anything that would break from a longer incoming hostname is already breakable through Velocity's own outgoing path. The decode/encode inconsistency doesn't protect anything if the encode side is already uncapped.
The security concern is fair, which is why the limit is Short.MAX_VALUE with decodeExpectedMaxLength kept in place, not removed entirely.
In my opinion it does not need to matter if upping the limit breaks vanilla backend compatibility if we put this limit behind a system property.
It's already possible to completely break vanilla (or any) connections with system properties by lowering packet size limits. Adding another system property that's a NOP by default, but allows a server admin to break vanilla connections (and fix support for EduGeyser) by increasing this limit isn't something new in that regard.
A system property that defaults to the broken behavior means every affected server admin has to independently diagnose a silent disconnect with no error output and somehow discover the flag. That's the same problem as the current bug, just with an extra step. The default should handle legitimate use cases without manual intervention. And to be clear, this has nothing to do with EduGeyser support. EduGeyser typically works fine without this change. These are general Velocity bugs that any plugin setup can hit under the right conditions.
I'm not understanding how allowing clients to send arbitary data inside of the handshake packet is
- for plugins
- a legitimate usecase
Mojang already offers a supported mechanism for plugins to sync arbitary data during early connections to the client, API here is lacking but I would much rather discuss proper solutions to that rather than having to maintain spec violations
The change isn't about allowing external clients to send arbitrary data. The longer hostnames come from plugins running inside Velocity, sending through internal channels like LocalChannel. External clients still send normal short hostnames.
Some plugins use the hostname field to forward data before authentication. This is the same BungeeCord forwarding pattern that Velocity explicitly supports, the limit was just set for DNS + Forge markers without accounting for forwarding payloads.
It's obviously not the intended use of the field, but I'm not the one introducing or picking that pattern.
Summary
Restore the full play-packet queue when a player connection reenters configuration state from play state.
This keeps the existing serverbound forwarding guards from the previous reconfiguration change, but avoids switching the client-side connection to outbound-only queueing during reconfiguration. Reentering configuration is a transitional protocol state, so both inbound and outbound play packets should be handled consistently until the configuration acknowledgement completes.
Root cause
The current code installs only PlayPacketQueueOutboundHandler when a play-state client is moved back into configuration. That protects clientbound play packets, but leaves the inbound side without the normal configuration-state queueing used elsewhere. In nested or rapid server-switch flows, this can leave the switch stuck waiting for reconfiguration to complete.
Validation
git diff --checkJAVA_HOME=/home/alex/.gradle/jdks/eclipse_adoptium-21-amd64-linux.2 ./gradlew check --c...
not sure why we'd be queing incoming play packets there, sounds like that was always a bad idea, should we not just be discarding them?
Expected Behavior
No CorruptedFrameException thrown
Actual Behavior
io.netty.handler.codec.CorruptedFrameException: Uncompressed size 12451 exceeds ratio threshold of 8448.0 for compressed sized 132 thrown
Steps to Reproduce
With a vanilla or paper backend, get a book & quill and write 30 pages with the following string on each page (copy/paste 30 times)
abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789
Plugin List
n/a
Velocity Version
Built from latest commit (9c0c9b02187c20bb767ce16ac7685580430d9b10)
Additional Information
This exception should not occur during vanilla gameplay (no mods, client or server-side).
This bug has been introduced since 9890c429, which tried to resolve decompression attacks. Apparently book contents sent from the client t...
I mean, highly repeating patterns compress very well, only real fix to this would be to remove the compression threshold restriction
I think this flag is fundamentally flawed, if we want to have zero impact on the vanilla protocol and what's expected with no modded or malicious clients. Increasing velocity.max-compression-ratio from the default 10 to 100 generates the same exception after creating a book with 100 pages (the maximum) of the long string in the description, this time with a decompressed size of 25404 and a compressed size of 183 (ratio of 138.8).
I mean, highly repeating patterns compress very well, only real fix to this would be to remove the compression threshold restriction
Yeah I agree. I assume this commit was another one to try to resolve the decompression attacks, right? I think we should take a look at merging #1786 soon. This PR resolves the actual underlying issue, rapid expansion of large packets in a short amount of time. The cause (9890c42) only looks at any individual packet, which may seem malicious but really isn't in this case. Again decompressed this is way less than 100kb for a s...
This PR also reverts ab8333d6944e844fb4152b561a0bee460a081216, see #1792. This commit is no longer needed as this PR resolves any threat of a decompression attack, this commit would kill legitimate connections way too soon.
adventure-bom = "net.kyori:adventure-bom:5.1.0"
adventure-text-serializer-json-legacy-impl = "net.kyori:adventure-text-serializer-json-legacy-impl:5.1.0"
Should be safe to merge since 5.1.0, right?
https://github.com/PaperMC/adventure/releases/tag/v5.1.0
For context, https://github.com/PaperMC/Velocity/pull/1088 is the PR that originally introduced the packet queue here, e.g.
if (state == StateRegistry.CONFIG) {
// Activate the play packet queue
addPlayPacketQueueHandler();
} else if (this.channel.pipeline().get(Connections.PLAY_PACKET_QUEUE) != null) {
// Remove the queue
this.channel.pipeline().remove(Connections.PLAY_PACKET_QUEUE);
}
in MinecraftConnection#setState.
I realized what we were doing was unidiomatic and did a big refactor internally now to use Velocity more idiomatically, so this isn't needed for me anymore, so will close. We were chaining velocity but after some consideration, it's not worth the trouble of patching velocity to make it work. We not just use one velocity + a plugin, which is way simpler and better.
Might still be worth looking into - chaining Velocity instances might not be explicitly supported but adding Velocity into the chain should not break the vanilla MC protocol.
Client - > Velocity_1 -> Velocity_2 -> Backend breaking suggests something is going wrong, either Velocity_1 breaks the vanilla protocol with the packets its sending serverbound, or Velocity_2 does not understand the vanilla protocol Velocity_1 is speaking clientbound.
The patch which this is partially reverting fixed a case of chaining, which is why I'm dubious on touching stuff here without further considerations
chaining velocity is itself a very complex issue because of nested configuration and our loads of patches were very annoying to maintain.
This is probably just worth merging for clarity when other developers are reviewing source
This bump is recommended, given: https://github.com/netty/netty/security/advisories/GHSA-rwm7-x88c-3g2p
Although Velocity doesn't explicitly enable ALLOW_HALF_CLOSURE, it's still worth tightening the gap.
https://github.com/PaperMC/Velocity/pull/1718 was previously successfully merged, hence why I reimplemented my various dependency bumps. This time around, I went ahead and handwrote each Javadoc entry and change.
These changes have been extensively tested and should perform accordingly!
Requested Feature
How about adding dialog box support?
Why is this needed?
To be able to use plugins to create dialog boxes for players in virtual worlds on Velocity.
Alternative Solutions
Don't know
Additional Information
No response
This is planend, we're waiting on adventure to add support for it. See PaperMC/adventure#1330
Hey @AlexProgrammerDE, would you be able to see if your issue is recreatable with the PR attached to this PR?
Can confirm, this still seems to cause issues.
PR is now ready for review! Tested and it fixes the real underlying issue (out-of-order chat delivery and queue stalls).
Since Adventure's Facet platform is now deprecated, maybe it's worth considering an alternative, similar to: https://github.com/GemstoneGG/Velocity-CTD/pull/883, @4drian3d?
I don't like this. But it works. RespawnPacket encodes the dimension as an int instead of a byte, which is where the actual bug occurs.
Reading this as an unsigned byte, then just writing it back as a byte in JoinGamePacket is a NOP. When switching servers, due to some weirdness with old clients we need to send a RespawnPacket that's generated off of this JoinGamePacket. That's when we write this previously signed byte as an int, resulting in a different value than the client expects.
This is a huge hack because we still need -1 to work for the nether.
I suggest changing the comment for why exactly this is needed, for future readers:
// Vanilla 1.7.10 uses a signed byte for dimension (-1 Nether, 0 Overworld, 1 End).
// Modded servers hack this to an unsigned byte to allow dim IDs up to 255.
// We must store the canonical int here because RespawnPacket.fromJoinGame copies this
// value into a packet that encodes dimension as a 4-byte int (RespawnPacket.encode,
// pre-1```...
References:
- https://c4k3.github.io/wiki.vg/Protocol_History.html#18w30a
- https://bugs.mojang.com/browse/MC/issues/MC-132663
- https://github.com/PrismarineJS/node-minecraft-protocol/issues/60 (best reference I have for < 1.13 being 32767. This highly seems to be the case.
This is exactly how BungeeCord does it: https://github.com/SpigotMC/BungeeCord/blob/master/protocol/src/main/java/net/md_5/bungee/protocol/packet/TabCompleteRequest.java#L44
Inspired by #1681, but with the correct values.