#velocity-dev
164 messages · Page 3 of 1
lololo np i appreciate the help
nO, we use protocollib but not protocolsupport - and we don't use viaversion
show your code you use to send the messages please
Leaving it for now, I'll be back in a little bit to try again just so you know I'm not ignoring, thanks for the help
Hello I am working with code that has the following dependency...
implementation group: 'com.velocitypowered', name: 'velocity-utils', version: '4.0.0-SNAPSHOT', changing: true
I've been looking around and the highest I can find is 3.0.1 is "velocity-utils" something separate? What's the latest version?
Long story short seems like they used their own implementation with stuff that's just missing right now, wondering if anyone is willing to help me figure out how to fix the log4j error.
Exception in thread "main" java.lang.NoSuchFieldError: EMPTY_BYTE_ARRAY
what's a velocity equivalent for being able to use a gradle property thingy like ${version} in the plugin info. previously used ProcessResources but i'm unsure how to apply that to the annotation-based thingy
found kyori blossom
kyori member discovers kyori project
How can I take advantage of velocity's api to make a plugin that allows players to join my proxy and be proxied to an external server (like Hypixel)?
Minecraft doesn't support transferring players like that
It's not really about Minecraft
I am trying to use velocity as a proxy to imitate a player
Which is proxying
Player -- joins --> [My server]
[My server] -- forward's Players' connection --> [Hypixel]
You wouldn't be able to make them join online mode servers (without having them sign in somewhere) because the player's authentication is only valid for the server they joined, your proxy.
Ah I see, so you're saying that I would need to authenticate with Hypixel, but that information isn't sent to directly Velocity (so I can't "forward" it to Hypixel)?
Actually that doesn't make much sense because if I recall correctly, Velocity doesn't do anything but act as the Player when connecting to backend servers.
Velocity also handles authentication with mojang servers
Unless it's only because the backend servers has to specify to only accept connections from "x proxy"
The minecraft client will only authenticate once (LOGIN phase)
Then the connection is established
(PLAY phase)
To prevent servers from hijacking users accounts it’s only possible for the client to be in LOGIN once per connection
If you want to join another server over a proxy like velocity you’ll have to modify the proxy;
Essentially: You need the proxy to sign into your account again; and do the same thing with the server you’re trying to join as your client did to log into the proxy
That is, you need to provide the proxy with a session or your account directly so it can do that
Not a very useful idea sadly
I see. Well it’s possible at least
if you give the proxy the session token maybe
but that's not smart
is PreLoginEvent the first event on connect where you can deny the connection?
Is there a ping-ratelimit available via Velocity which will rate limit pings per IP, or is that something which should be handled by a plugin on the proxy
just want to see what level it should be resolved - and if it could be a feature within velocity (I'm willing to throw in the work for it if it's not available currently)
I know there's a login-ratelimit but that still leaves the ping exposed from what I understand
Technically no, the handshake event is earlier; but I wouldn’t recommend doing anything there
Hi, does anyone have some code examples with a task scheduler?
looking at the JD I don't think that has a deny/cancel method, also why not :p?
Because the client doesn’t have a way of being disconnected correctly at that stage. You can get the inbound connection from that event however ….
Seriously not recommended though
with bungeecord, you send a plugin message packet with the channel "bungeecord" to switch servers. Does anyone know what you have to do for velocity?
The same. Velocity supports the bungee channel api
We didn’t reinvent the wheel for that one, plus, it makes more plugins compatible with velocity
ah okay thanks
How do I get players from a specific server?
I want to take all players who are on the server of a certain player
Ok
Get a list of players, filter out those who aren't on the server you're looking for...
player.getCurrentServer().get().getServer().getPlayersConnected()
turned out without filtering
Hi guys im trying to redirect a player when servers stop with Velocity but it just disconnects players for the reason the server stopped
because the only thing that matters is the combined player cap of all accessible servers behind the proxy. Velocity does support changing the displayed slots tho
right
I thought that maybe some people would want something like that
but that would be easily done with a plugin
Hi, what is the best option to communicate between Bukkit <-> Velocity? Is it possible to use the integrated plugin messaging channel? Should I use it or should I choose other alternatives like RabbitMQ?
Depends. Yes you can, if players are available. Message Brokers work too, but if the proxy is static and less event driven, could also use grpc
Hmm, is there any documentation on how to receive plugin messages on velocity?
Well certainly isn't much helpful, can you please link it?
Unfortunately not, i am only on my phone and haven't looked at the docs for a while, so I just wanted to express there most certainly is one and someone else will hopefully chime in
I really wasn't able to find it tho
https://github.com/VelocityPowered/BungeeQuack/blob/master/src/main/java/com/velocitypowered/bungeequack/BungeeQuack.java is very old, but maybe you can find similar stuff
Unfortunately it is for Velocity 1.x So it isn't really relevant, I'm gonna use rabbitmq anyway.
Why can't the infiniburn setting here be empty? https://github.com/PaperMC/Velocity/blob/b8f1df44707d80ca48a0fa924e0bfc5927f54863/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/DimensionData.java#L91
wiki.vg mentions it can be empty, and the game seems to handle it correctly
Between intended and working way of doing things we intend to go with the former rather the latter
I see, I didn't know it was intended to be required
What's the best way of communicating between server and proxy?
plugin messaging channels
or redis/another pub-sub solution
I thought plugin channels were dependent on a player...
They are, if you need to not rely on players than do the second thing I said
Redis/another pub sub option is good
any idea? Error: "java.lang.NoSuchMethodError: 'com.velocitypowered.api.proxy.server.ServerPing$Builder com.velocitypowered.api.proxy.server.ServerPing$Builder.description(me.kerpson.proxy.libs.net.kyori.adventure.text.Component)'
"
in ProxyPingEvent
You can't relocate adventure in your plugin and use the platform native methods
it works, thanks
Hi, my servers are dynamically managed by a cloud software, is it possible to set fallbacks?
If a player got kicked by a server he got kicked off the full network
Same problem
So any method to set player fallback?
KickedFromServerEvent#setResult
hi
java.lang.NullPointerException: Cannot invoke "java.lang.CharSequence.length()" because "this.text" is null
at java.util.regex.Matcher.getTextLength(Matcher.java:1769) ~[?:?]
at java.util.regex.Matcher.reset(Matcher.java:415) ~[?:?]
at java.util.regex.Matcher.<init>(Matcher.java:252) ~[?:?]
at java.util.regex.Pattern.matcher(Pattern.java:1134) ~[?:?]
at com.velocitypowered.proxy.plugin.loader.java.JavaPluginLoader.loadCandidate(JavaPluginLoader.java:68) ~[velocity.jar:3.1.1]
at com.velocitypowered.proxy.plugin.VelocityPluginManager.loadPlugins(VelocityPluginManager.java:92) ~[velocity.jar:3.1.1]
at com.velocitypowered.proxy.VelocityServer.loadPlugins(VelocityServer.java:324) ~[velocity.jar:3.1.1]
at com.velocitypowered.proxy.VelocityServer.start(VelocityServer.java:222) ~[velocity.jar:3.1.1]
at com.velocitypowered.proxy.Velocity.main(Velocity.java:64) ~[velocity.jar:3.1.1]
[19:24:14 ERROR]: Unable to load plugin plugins\SpicyTacos.jar
com.velocitypowered.api.plugin.InvalidPluginException: Did not find a valid velocity-plugin.json.
at com.velocitypowered.proxy.plugin.loader.java.JavaPluginLoader.loadCandidate(JavaPluginLoader.java:64) ~[velocity.jar:3.1.1]
at com.velocitypowered.proxy.plugin.VelocityPluginManager.loadPlugins(VelocityPluginManager.java:92) ~[velocity.jar:3.1.1]
at com.velocitypowered.proxy.VelocityServer.loadPlugins(VelocityServer.java:324) ~[velocity.jar:3.1.1]
at com.velocitypowered.proxy.VelocityServer.start(VelocityServer.java:222) ~[velocity.jar:3.1.1]
at com.velocitypowered.proxy.Velocity.main(Velocity.java:64) ~[velocity.jar:3.1.1]
there is no trace of velocity-plugin.json in the documentation of velocity
please don't ping random people Qg
it's generated with the plugin annotation
assuming you've set it up correctly
are you using maven or gradle?
sorry it's a fail
gradle
Please send large files/logs to a pastebin
A sensible, modern pastebin. Share text and source code snippets with no hassle.
id 'java'
id 'com.github.johnrengelman.shadow' version '6.1.0'
}
group 'fr.qg'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
maven { url 'https://repo.velocitypowered.com/snapshots/' }
}
dependencies {
compileOnly 'com.velocitypowered:velocity-api:3.0.1-SNAPSHOT'
annotationProcessor 'com.velocitypowered:velocity-api:3.0.1'
implementation 'com.google.inject:guice:5.0.1'
}```
paste your build.gradle
oh you do have it defined as an annotation processor, that looks correct
Show what’s in your @\Plugin annotation
Uh you have any invalid package names?
what are you running to build it?
oh that's it, I use the shadowjar
That’s fine
run with --scan and post the link here, idk what else this all looks correct
you've got to activate it/agree to tos first
just untick "Subscribe to the Gradle newsletter"
Can you see what the generated velocity-plugin.json looks like?
Make a plugin with annotation processor then open the jar?
{"id":"spicytacos","name":"SpicyTacos","version":"1.0-SNAPSHOT","description":"I did it!","authors":["Qg"],"dependencies":[],"main":"net.hyna.spicytacos.TacosPlugin"}
and is the velocity-plugin.json in the root of the archive?
hi there, I don't have a velocity-plugin.json file in my jar even though I do have annotationProcessor set like so: https://github.com/StackDoubleFlow/ChattORE/blob/36ac869a02f2a566930d8a0898cee0c3fcd002aa/build.gradle.kts#L41
If it’s kotlin you need kapt
ah
Does velocity have messaging channels similar to bungee? Or should I just use BungeeMessageChannels as I believe it supports them
It uses the bungee ones
Hey there,
does velocity has something like Bukkit Scheduler ? also is there any API guide for beginners?
https://jd.velocitypowered.com/3.0.0/com/velocitypowered/api/proxy/ProxyServer.html#getScheduler()
You can create tasks with the builder
https://jd.velocitypowered.com/3.0.0/com/velocitypowered/api/scheduler/Scheduler.TaskBuilder.html
Basic guide to plugins:
https://velocitypowered.com/wiki/developers/creating-your-first-plugin/
Thank you, appreciate it.
I checked the API, but seems there is no built in configuration system for plugin configuration folder, if true/ is there a method to get plugins/velocity/data directory?
@DataDirectory, check the wiki
(bottom of https://velocitypowered.com/wiki/developers/api-basics/) @teal adder
oh I skipped that part, thx
i have a problem with batch inserts
when i do a batch insert and return generated keys it only returns 1
hi
What is the difference between using asynchronous events and using sync event with asynchronous ?
What is the benefit of it
i don't understand what is the difference between velocity async event and sync event with classic async
Hum.. the first solution, the event is sent asynchronously and all handler are executed in the concurrent thread
And the second solution, the event pass through the queue of event in the main thread, each handler is execute in the main thread and after, you will free the main thread using another thread
So.. the best of course is the first, but if you doesn't have the choice, the second solution can save a bit
I think this explanation is correct 🤔
so if one plugin decide that an event is asynchronous then it will be for all other plugins ?
it makes sense but it's not clear
Normally, if the developers decide that an event is asynchronous, all instance received of this event (in each handler) is in a concurrent thread of main thread in all cases
(Except if there is an error in the implementation.. but .. probably not)
To be sure and try you can just print the current thread when you receive event
Asynchronous events allow asynchronously resuming execution of event listeners at a later point in time. The advantage of this is performance; threads need not block..
Okay thanks i'll test, because if there is two events handler, one with priority last async, and the second with priority first but sync, will the two events be on a different thread ?
Or it's only all the event handlers after the first one that decide to work on another thread ?
I'll test it out today
Yep but will it stop other event handler ?
Or other event handler compute the event, and then at the end, the event "waits" for the async event handler to finish ?
Because on bungeecord there was some of events fired asynchronously that's why im a bit confused
Like if we have A1 an asynchronous event with the first priority, and then S2, a synchronous event with the last priority
Will the execution be :
A1 -> S2
With A1 asynchronous and S2 asynchronous too ?
hum .. In this case, i can't help you, i never test this situation
Do pluginMessageChannels work the same with velocity as they do with bungeecord?
Or do i have to use a diffrent way to execute proxy functions in a paper/spigot plugin
For some reason my signs plugin still works? I can click the signs and it will put me in the correct server. Even tough i didnt change anything and it still uses the Bungeecord channel?
They work the same as bungee, just register tham as you would for bungee.
Yeah i just noticed that. I havent changed anything and my "bungee" signs plugin still works
Thats neat 🙂
It should do, Velocity just uses bungee messaging channels for simplicity. I personally use redis to communicate most of the time, but that's just personal preference.
That would also work. But i only have 1 plugin that gets me the information how many people are on the server and then sends them to the specific server
So the extra work is probably not worth it because its a personal server where only my friends play
That's understandable, I only did it that way because it was for a large network!
hey i'm starting to learn how to develop a velocity plugin for a global chat and i noticed the server.sendMessage() takes a component. what is component or where do i find documentation for it? not sure if i did something wrong with intellij but i can't like auto-fix the import.
Kyori is probably the best thing to look into
It’s what velocity uses
#community-guilds message this is the discord link
alright i'll go over there, thank u
OH ITS ADVenture like the thing that paper recently merged. now Component makes sense!
Yepp
Hello, does this looks correct?
server.getScheduler().buildTask(this, new RAM()).repeat(20L, TimeUnit.SECONDS);
Yup, to actually schedule it, call #schedule() on the builder
Appreciate it 😄
do someone has a clear example of what is the differences between the two and what happens if multiples plugins use sync AND async events on the same event ? Thank you ! A scheme would be the best
async means run in parallel, basically
right now, all events are basically fired async
continuation is basically akin to figures
task 1 finishes, it will run task 2 (i.e. the continuation)
(the continatuon just really seems like its for repeating tasks, but, idk there)
oh, that's one of the primary use cases, otherwise, what i said, futures more or less
that's why it's a bit confusing for me, so flagging our event with async flag just mean that the event will skip to the next event handler and then comeback when our event computing is done ?
the async thing is just to tell that the other events handler can process the event and then comeback to our event handler when it's ready ?
No
all events are async
whenever you fire an event, it's ran on another executor
This thing just seems like a massive ass mess in which the best thing I can suggest is reading the documentation of how it works
or, I mean, the implementation
Will @Inject only work on the main class of the plugin or can I use it in my sub packages as well to inject the server instance?
Should work everywhere unless you use a custom class loader
Though there is a tiny chance I just don’t have that part of the code in mind correctly; but I’m petty sure nonetheless
Okay that's cool, thanks
.
Wrong channel #paper-help
👍
No, not with regards to velocity's async events. Rather, listeners run in sequence, but resume asynchronously.
It won't "stop" the other event handler; it will delay the next event handler's execution until the current handler is finished.
Sync event handler -> Async event handler .... long async computation ... -> Next event handler
I mean, i was explaining what async meant, didn't entirely relay it into what velocity does too much
the code there just looks o.O
so what's the difference with sync event handler since every handler are run sequentially
and electroniccat said that all event are not on the main thread
Sequentially is not the same as "not on the main thread." Listeners are run in sequence: one after the other. However, async listeners can choose to resume execution at a later point in time
from what I saw, looked like they ran on their own special thread
Async listeners can therefore listen to the event, handle it and perform some computations on another thread (hence "asynchronously"), before finally resuming execution
bearing in mind that there is no main thread in velocity
But, that logic was running through a good chunk of stuff, so, I am probs wrong on some of what I saw
Velocity moves execution of event handlers to a thread pool after the first async listener (or thread-pool-requiring-listener for backward compatibility) is encountered
Okay and while the async compute the event, the others listeners can compute in parallel too ?
No: only one listener will execute at a time.
This is the meaning of "sequential" when I say that the listeners run in sequence.
But what is the point to perform computation on another thread since the thread the listener is using is already async ? Or is the thread used by the listener by default is used by other stuff ?
i think im starting to understand the differences
We use threads for various purposes. There is not one purpose of a thread: I think you are carrying the assumption that the only reason we use threads on a Bukkit server is so that we do not block the main thread.
On Velocity, multiple threads are still used, even though there is not a main thread. However, it is common to run certain operations on some threads, others on different ones. Consider Velocity's own threads: Velocity has a handful of threads on which the netty event loop is run; these are sometimes colloquially referred to as the "netty threads" by plugin developers.
Plugins use threads for still other purposes. Many plugins connect to a database. A common practice is to create a connection pool and a suitably matching thread pool, such that the thread pool and the connection pool are most effectively used together -- for example, if the number of threads equals the number of connections, and both pools are fixed in size. This makes for the best performance.
You may be wondering why we don't simply pool all of the threads, everywhere, into one thread pool. The reason for that is some thread pools require different characteristics. Some thread pools are fixed in size, some growable. The growable thread pools have settings for the expiration time of idle threads and thresholds under which threads will be created more eagerly.
Okay thank you for your precise answer !
So for example if i want to do a query on a database, i just use an async task or a connection task rather than a sync task with my own threadpool ?
That would be a common way of doing things, yes. I'm not sure what you mean by "connection task," but I think you understand the concept. We use threads for raw performance, organization of computations, and fine-tuning performance for certain computations (the last item relying on the second one).
It is common in Java, also, to name thread pools, so that it is easy to identify software responsible for certain threads in a thread dump. A thread dump is a report of all threads currently in operation; thread dumps are useful to debug deadlocks and general concurrent processes in the program.
Why is Velocities Configurate so OLD O_O
I have really appreciated the help that I have got before, but I have one question. Do I need velocity plugin kotlin for kotlin use in plugins, or can I just add the kotlin stdlib to my outputs, like I do with bukkit plugins. If I have to use the kotlin plugin for velocity, I would appreciate if someone tells me how I add this to my plugin.
velocity doesn't include kotlin so you'd need to include it in your plugin
i mean
is this maintained
oh that, i mean yeah that's got a version for 3.x if you're okay with a slightly outdated version of the various libs it includes
thanks
sorry for spamming the channel again, but in the docs, and the java docs, I was looking for a way for the velocity plugin to recieve a plugin message from a player
i want to do something like this
The home of Spigot a high performance, no lag customized CraftBukkit Minecraft server API, and BungeeCord, the cloud server proxy.
but in velocity
i need this feature, because, Citizens2 does not support calling velocity commands
so I have to make a plugin for paper, that sends a plugin message telling the proxy to execute some code
(this code is some loadbalancing and looking for the optimal server)
(that's for receiving and sending messages in Velocity, consult your backend server's docs on how to send messages to a proxy)
Feel free to make a PR 😉
If I remember correctly, Velocity handles stuff in different threads. When I wanna create a player hashmap to keep the last server they where on for 30+ minutes or smth like that to send them to the same server on rejoin will join, leave events always run in the same thread or to I have to make the map threadsafe?
Atm I think I have to do it the second way
do a ConcurrentHashMap<UUID, RegisteredServer/ServerInfo>, that should work for what you need
Wym by cache
I never used them, was thinking about Fives solution but I'm going to check them out now, thx
Well, Fives solution would work, just without the time thing
Yeah I wanted to implement the removal on my own, but I guess the cache implementation already those that for me
Have to check it out
Working on a new velocity plugin (I'm new to developing for velocity) and I am able to run the commands I have registered from the console but not from a player with the correct perms. Either getting "Unknown command" or invalid args message in return. Has anyone seen this behavior before (or is it expected?). Thanks!
What are you using to apply the permissions
@oblique haven LuckPerms, it's installed on the proxy and individual servers as well (both running paper)
You might want to have something spit out the result of the permission checks on join or something
and you did set the permission you used as condition on the proxy?
/lpv is the correct command for LP on velocity unless you linked the proxy and server(s)
The proxy and the individual servers are all linked via mysql database, and doing lpv user <username> permission check <permission> with the correct args in for the perm as well as the username come back as expected (true)
Mk, can you show us the command and the registration along with the command you’re using or trying to use
With the args and everything
something must be wrong so
Is it alright to send screenshots in here?
Here's the command class (StaffChat referenced)
Here's the main class with the registration
Have you tried putting debug into the invocation to see if it’s even being run
Or printed out the result of the permission check
I'll go try that now
Sorry this took a second I had to step out, the permission check is failing
So how else should I be going about doing the permission check?
Ahh I just figured it out, my Luckperms hadn't synced properly and reseting everything cleared it up. I apologize for the inconvenience
API is so much cleaner than bungeecord
The best part of Velocity
So, yeah I just started the test on this cache thing 5 min ago. Now the only event for logout I found in the docs (may I oversaw one) is the "DisconnectEvent", now I made a lil test setup if(event.getPlayer().getCurrentServer().isPresent()) logger.info(event.getPlayer().getCurrentServer().get().getServerInfo().getName()); because I did not know if the "getCurrentServer()" is still available at that point – as far as I see it is. But since it is an Optional, may it be not set at that point if the user was connected to a server before or is the DisconnectEvent being fired always before finally disconnected and cleared?
Like I understand that is optional since it could disconnect from the proxy without ever being connected to a server but if the player had a server connection before
I'm also just trying to figure out what of the Login or connect events might be the best to interrupt if a previous server has been found in cache.
Because the timer is running
if you take too long to let that event carry on, you can prevent a client from being able to join
so if i need, for example, to check if the player is banned on a very slowly database (like 5 seconds of response for example), i need to accept the event (not cancel it) and then when i have my response i kick him from the proxy ?
Yes
okay thanks
and is there a way to manipulate yml config file like waterfall ?
or now it's all toml file ?
before we had this, is there an equivalent in velocity ?
How is it in my case, should I also let the proxy finish the login progress and reconnect to another server after or while connecting to a server or is it safe to send the connection request already while the login event on the proxy itself?
in your case i think that a hashmap#get is really quick so it will be fast enough
Hmm still not sure what "fully initialized" might be, like difference from LoginEvent to PostLoginEvent
Put I guess PostLoginEvent might be the best option
from what I see, of all events
the fully initialized is in the PreLoginEvent right ?
LoginEvent is also after Mojang
yes
i believe PostLoginEvent is when the player has the server he is about to connect to
A I finally found it, was hidden asF 😄
PlayerChooseInitialServerEvent
it also has a setter method
and do you know how to manage config file ?
I probl will not use build in stuff this time, since I have to merge Spigot, Bungee and Velocity later, so I did not look it up so far
But if you search for a way to do it via toml, that might help you https://forums.velocitypowered.com/t/plugin-configuration-file/327
I will go with yml
Well looks like it works with caffeine cache just fine, time to go to bed. Will clean up the code tomorrow. Thanks for help

Thanks i'll look
hi, is the client unable to receive messages during ServerConnectedEvent? i'm sending a "$player switched to $server" immediately and it shows up for everyone except the one switching
i'm going to try using ServerPostConnectEvent right now but i'd still like to know whats happening
yes it could be too early for them
i think that was it, fixed by using serverpostconnect
What do you mean by that
Hello, I'm currently trying to connect to a MySQL database in my plugin.
I'm having an issue where it cannot load the driver:
java.lang.ClassNotFoundException: com.mysql.jdbc.Driver
I have looked online and found I need to include this via a class path, so I have added the following into my code before the driver is used:
server.getPluginManager().addToClasspath(this, Path.of("lib/"));
However the issue still persists, I have included the driver in the lib folder.
Please let me know if I need to do something differently. Thanks!
I had better luck with literally just running Class.forName to the driver after including it as a shaded and relocated dependency
does the addToClasspath thing 1) modify the classpath seen by currently loaded plugins 2) work in a useful manner to actually load jars in a folder?
idk how the classloaders care when you pass a dir to them as stuff is generally resolved there
Yes to 1.
Yes to 2.
The URLs in addToClasspath are passed directly to URLClassloader#addURL
Ah, specifying the jar in the folder lib/mysql-connector-java-8.0.27.jar has done the trick!
However now its saying that driver is obsolete and I should use "com.mysql.cj.jdbc.Driver" instead
Moreover, you should isolate your dependencies from other plugins.
well, you're calling Class.forName on the old class
the class it's telling you to use is where they moved stuff
player2.playSound(Sound.sound(Key.key("BLOCK_BELL_USE"), Sound.Source.MASTER, 1, 3)); shows me a warning in the first parameter Key that it doesn't match regex
Velocity doesn’t support sounds iirc
aight but I thought it does because the playsound method exists
From adventure
fwiw, that sound isn't a sound anyway
adventure provides the ability to play sounds, if implemented - velocity implements adventure but chooses not to implement the ability to play sounds
This isn’t implemented because that would require velocity to keep track of player and entity positions. It’s extra load that’s not justified for a proxy
you don't need to keep track of that stuff, the main issue would be with holding a resource mapping of sound -> id which is tricky
is there a broadcast thing like waterfall ?
That’s not the entire issue, if you want to do it right you do have to track locations and entity IDs; And that all varies with version
ProxyServer extends Audience so it has the same sendMessage(Component) function as players do if that’s what you’re asking
How can I force a player to perform a command or go to a different server?
I want to make a lobby compass that can take you to different servers. If I could do something like Player.performCommand("/server lobby") but for Velocity commands, that would work.
i mean you can do spoofChatInput but you could just move them to the other server directly
player.createConnectionRequest().something i cant remember
yeah, player.createConnectionRequest(server) and either .fireAndForget() if you don't care about the result, or one of the other methods if you do care about the result
Thank you, I got it all figured out.
Quick question, are the Watterfall and Velocity UUID's the same, because there are different ways to get those on both sides, thank you for your answer in advance.
Yes
is there an equivalent of ChatColor.translateAlternateColorCodes('&', message) ?
you can use the legacy component serializer
or just just a non-legacy, modern format like minimessage
what ?
read up on kyori’s LegacyComponentSerializer or just use MiniMessage which is more modern
have you an example ?
like if i want to send a message that looks like "&1Hello&2World"
Minimessage uses some weird html tags
ampersand arbitrary letter user calling tags weird
again, you can just the legacy component serializer
see docs here ^
i already read it but sadly there is no example
Do I need some Velocity plugin to put in my server? I keep getting this error Caused by: java.lang.ClassNotFoundException: com.velocitypowered.api.proxy.Player
uh, velocity is a proxy software - you can't run velocity plugins on your server software
If I move it in the proxy plugins folder, I get this, Exception in thread "main" java.lang.NoClassDefFoundError: org/bukkit/plugin/java/JavaPlugin
Please send large files/logs to a pastebin
A sensible, modern pastebin. Share text and source code snippets with no hassle.
that error sounds like you tried to put a Bukkit plugin on a Velocity server
I mean, you put a velocity plugin on a bukkit server
I'm trying to make a lobby compass. And to do that, I need access to com.velocitypowered.api.proxy.Player
and then you put a bukkit plugin on a velocity server
No
I mean
you can't access that class from the server
use the plugin messaging channel
I mean, you'd do that from the server, in which see the spigot wiki
they have a full page dedicated to the bungeecord messaging channel
(velocity reimplements that itself)
I cannot find the page that you are talking about.
Thank you, everyone. I got it working.
Guys if im making a cross platform plugin and a universal jar, and i wanna use kyori's adventure, i can shade it but for velocity this probably wont work
Am i right?
cross what platforms?
blimey, well
id recommend not doing that
but if you absolutely have to for some god forsaken reason, split your stuff up into different modules
Relocate it and just don't think about it, or exclude the dependency in the velocity module
well if you relocate adventure then nothing on velocity will work
if you shade it then velocity might throw a fit
so like, gl ?
Ofc i would do that i mean i need universal jar
you don't need a universal jar
look at, for example, luckperms - they don't produce a universal jar because of how annoying it is
universal makes sense when you can contain shit
If i put it on spigot which jar i should upload lol 😀
the spigot jar?
when you start getting into platform oddities, stuff starts going sideways, especially with cases where some deps need to be shaded, some deps would be harmful
Spigotmc website i mean
they have a bungee and a spigot plugin section
you'd basically have to upload it twice if not universal
or link to a downloads page
if you hated yourself there is the horrors that LP does where he can decide programatically what's pulled in
I don't want those aternos users to kill me in reviews section
but, that's a headache
Ok thx anyways
just save yourself a headache and keep stuff separate whilst still having a common module you can keep common stuff in
I'm writing a server implementation that would conveniently provide support for velocity as a proxy, but I'm having hard time finding any official documentation about the exact plugin messages being exchanged between server and proxy, there's nothing on the website or the Github. (At this moment I have already reverse engineered it) I think that adding this information to the developer documentation will be useful for others along with myself! thanks!
I don't think it would be rejected if you made a PR to the docs, but I doubt anyone is going to go out of their way - it's trivial to reverse engineer it from the source and existing implementations (source: I did it for fun years ago when Velocity first started)
true enough, I'll reconsider when I have time :)
Hey @fossil sundial I seem to remember you have a velocity 3 autoupdate script, would you be able to run it on this plugin it used to be quite handy on my server. https://github.com/Tobi406/Aliasr
Is there a similar feature to Bungeecord/Bukkit setCancelled(true)? I am trying to stop a message being sent under specific conditions and I have tried:
event.SetResult(PlayerChatEvent.ChatResult.denied(), but the message is still being sent.
Disable username validation in your paper.yml
Also this is the wrong category entirely
That’s the correct way
Which kind of message are you trying to cancel? This doesn’t apply to commands or things sent from server>client or proxy>client
hi
i tried to create boss-bar for 1.8.8+ in one of my velocity plugins
declaration: package: net.kyori.adventure.bossbar, interface: BossBar, enum: Color
but the boss-bar it's working just for 1.9+ players
seems legit
bossbars where tied to entities in 1.8
So, not supported as the game didn't support standalone bossbars then
Is there other variables that we can inject in the plugin constructor ? Except for the ProxyServer, Logger and directoryPath ?
Just whoever someone chats in chat. I am using the PlayerChatEvent. Everything else does work besides that. I can do some more testing later today.
Hi, I would like to know if it was possible like on Spigot to build its libraries in a folder next to it so that they are not included in the jar so that it is less heavy
What else do you need?
Is there an way to get the Players UUID who is Pinging the Proxy (ProxyPingEvent)?
No
Ok ): Thx
no because he is not authenticated with mojang
Uuid comes when the player is authenticated with mojang
you can hold a cache of IP -> UUID and effectively guess
That's a suitable solution , thanks.
that works for the cheesy messages, kinda
but, then you get to dynamic IPs
CGNAT, etc
But if its only for a short term job its possible( 10 minutes or something like that)
How would i get the IPs of the server under the proxy and their player count in a paper plugin?
The bungee way does not seem to work. I send players to servers with the message channel but not get the ip and playercount
Why would you do that ?
Maybe stupid question, but how can I get the main class instance of plugin (with @Plugin annotation) in another class?
You can pass it using dependency injection, i.e. pass the plugin class instance as an argument to the constructor of the class that needs access to the plugin instance
You can then store it in a member variable
I dont think that is how you register a command. When i tried it, it gave me an error because you have to put the Name first and then the method.
Or is it because this documentation and the one on this site https://velocitypowered.com/wiki/developers/command-api/
Are written for diffrent versions?
It's at the end of this page
CommandMeta meta = commandManager.metaBuilder("test")
// Specify other aliases (optional)
.aliases("otherAlias", "anotherAlias")
.build();
and then
commandManager.register(meta, new TestCommand());
The pages under this subdomain are for an older version of Velocity and are only kept online for archival purposes (afaik)
Hmm Velocity has a lot of very scarcely documented launch flags
Here is the full default set
-Dvelocity-forwarding-secret=<config>
-Dvelocity-packet-decode-logging=false
-Dvelocity.natives-tmpdir=$tmp
-Dmojang.sessionserver=“https://sessionserver.mojang.com/session/minecraft/hasJoined“
-Dvelocity.increased-compression-cap=false
-Dvelocity.natives-disabled=false
-Dvelocity.disable-native-transport=false
-Dvelocity.log-server-backpressure=false
-Dvelocity.max-packets-per-flush=8192
do we need to always use concurrentMap in commands and events since there is a lot of thread ?
depends on what you’re trying to do? I don’t understand your question
someone told me that velocity use poolthread for his system, so if for example i use a Map in a Command or an Event, do i need to set the map as ConcurrentMap to prevent that two threads use the same map at the same moment ?
Well yes, if you need to store data outside of the command execution chain you need to ensure its thread-safe
but if i use the map inside the execute() method it's okay ?
Or within an event handler ?
again, if you don’t modify or access data outside of your execution chain that might be accessed by something else at the same time you don’t need to ensure concurrency.
nice thanks
the concurrency model of velocity is honestly kinda confusing
I remember tryna work some stuff out other day and that's probs what killed me off for the rest of the week
#ThxFive
if I have a Spigot EntityType, and I convert it to Mojang EntityType with CraftMagicNumbers.getEntityTypes(type) how do I check if the resulting type is EntityType<? extends Mob> it seems like its very confused because it returns EntityType<?>
if I do instanceof I guess it doesn't do much because both of them are EntityTypes and its not checking the generics
o shoot omg
yep that's why i put ConcurrentMap and Set everywhere lol
a tiny bit "slower" but not notable so...
So im trying to convert a string containing a RGB value into a color value
󌝴Hello World for example could be a string with a RGB color value
For some reason it's only parsing the final value of the RGB, In this case it would be &2Hello World
private static final Pattern pattern = Pattern.compile("&#[a-fA-F0-9]{6}");
public static String color(String s) {
s = format(s);
Matcher match = pattern.matcher(s);
while (match.find()) {
String color = s.substring(match.start() + 1, match.end());
String color1 = s.substring(match.start(), match.end());
s = s.replace(color1, ChatColor.of(color) + "");
match = pattern.matcher(s);
}
return ChatColor.translateAlternateColorCodes('&', s);
}```
I've seen other velocity plugins use RGB values like #938203, but i want to be able to use it as 󥃛
Any ideas?
use the legacy component serializer
How do i call that?
you'll need to build one
Are there any existing examples to save time on research on how to do that?
// store this somewhere
LegacyComponentSerializer serializer = LegacyComponentSerializer.builder().character('&').hexCharacter('#').hexColors().build();
// use it like
serializer.deserialize(string);
Hmm so if i wanted to format &7Hello World (or with a hex) i'd just call serializer.deserialize("&7Hello World")
yes
oh, it's serialize then
Component is the data representation
or, the true one
if you wanna serialise to legacy, you pass in a component
if you wanna read legacy, you deserialise it into a component
Ahh thanks a bunch you two
If we do legacy forwarding what we have to configure in servers
Online mode
LOL
i would use auth me, their velocity plugin + authserver spigot plugin
online mode yes
why accept crack, it's 2022, the game is only 25 dollars everyone can afford it
ping server
i have a weird bug with velocity
when i do this, it says that the command is unknown, normal i don't have the permission
but if i do that
it prompts an error
i don't have the permission too
normally it should display the same output "Unkown command"
No, that's expected behavior and follows what Brigadier does
It's not really intuitive, blame Mojang /shrug
Why does my server logo not work?
It works on my backend servers fine and when I add it to proxy it just goes black.
You're asking in the wrong channel.
Trying to create a simple custom tab list, having trouble with it
I am able to see the custom tab list for a millisecond when a player logs in but it instantly resets to just a vanilla username
public class CustomPlayerlist {
@Subscribe
public void connect(ServerConnectedEvent event) {
update(event.getServer());
}
@Subscribe
public void disconnect(DisconnectEvent event) {
update(event.getPlayer().getCurrentServer().get().getServer());
}
public static void update(RegisteredServer server) {
FileConfiguration c = Config.DEFAULT;
for (Player playerToUpdate : UKMC.getServer().getAllPlayers()) {
GameTablistUpdateEvent event = new GameTablistUpdateEvent(playerToUpdate);
GameEvents.fire(event);
if (!event.isOverridden()) {
for (Player p : UKMC.getServer().getAllPlayers()) {
if (!playerToUpdate.getTabList().containsEntry(p.getUniqueId())) {
playerToUpdate.getTabList().addEntry(
TabListEntry.builder()
.displayName(Chat.color(c.getString("tab.default-list"), p))
.profile(p.getGameProfile())
.gameMode(0)
.tabList(playerToUpdate.getTabList())
.build()
);
}
}
}
}
}
}```
UKMC.getServer().getScheduler().buildTask(UKMC.get(), () -> {
for (RegisteredServer r : UKMC.getServer().getAllServers()) {
CustomPlayerlist.update(r);
}
}).repeat(50L, TimeUnit.MILLISECONDS).schedule();```
(Also it is registered as an event)
Any ideas?
To my understanding, when packets are intercepted by velocity, the packet is decoded & encoded again, even when there is no change to the contents
Would it not be better to forward the original ByteBuf if the packet hasn't been modified?
then you gotta try and pass all that down the stack and deal with figuring out if it mutated, etc
You gotta decode it to be able to process it
public class SetSlotPacket implements MinecraftPacket {
private byte windowId;
private int stateId;
private short slot;
private ItemStack itemStack;
@Override
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
windowId = buf.readByte();
stateId = ProtocolUtils.readVarInt(buf);
slot = buf.readShort();
itemStack = ItemStack.readItemStack(buf);
}
@Override
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
buf.writeByte(windowId);
ProtocolUtils.writeVarInt(buf, stateId);
buf.writeShort(slot);
ItemStack.writeItemStack(buf, itemStack);
}
@Override
public boolean handle(MinecraftSessionHandler handler) {
if (handler instanceof BackendPlaySessionHandler backend) {
ConnectedPlayer player = backend.serverConn.getPlayer();
itemStack = Translator.translateItemStack(player, itemStack);
}
return false;
}
}```
I'm implementing Item translations like this. I think it would be relatively easy to cache the ByteBuf in the encode method, change whether it has been modified in the handle method, and if it hasn't, call `buf.writeBytes` with the cached buffer in encode
Obviously, the most difficult part of that is determining change from the MinecraftSessionHandler, but I don't think the caching requires a bunch of "passing down" like you said
the OG buffer isn't stored
Isn't the OG buffer passed into decode?
Yes, but none of the packets store that
Right, but I'm saying they could store that
Probably doesn't matter too much for the packets that base velocity intercepts
you'd basically need to slice the buffer or something
Since most of them are either very simple or don't occur that often (eg. JoinGame)
wdym? is it not possible to rewind it?
Well, if you get into marking it, yes
or, worse case scenario, just copy it twice
which then starts getting into consume the systems direct buffers or using heap buffers
slicing doesn't copy, iirc, it's retained towards the original buffer object from what I recall
it's basically just a sliced view, iirc
private ByteBuf cachedBuf;
private int readerIndex;
private byte windowId;
private int stateId;
private short slot;
private ItemStack itemStack;
@Override
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
this.readerIndex = buf.readerIndex();
this.cachedBuf = buf;
windowId = buf.readByte();
stateId = ProtocolUtils.readVarInt(buf);
slot = buf.readShort();
itemStack = ItemStack.readItemStack(buf);
}
@Override
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
if (true) { // if(!changed)
cachedBuf.readerIndex(readerIndex);
buf.writeBytes(cachedBuf);
return;
}
buf.writeByte(windowId);
ProtocolUtils.writeVarInt(buf, stateId);
buf.writeShort(slot);
ItemStack.writeItemStack(buf, itemStack);
}```
Sorry for code dumps, but this naive approach seems to function
Hey, quick question: Is there a reason for everything being Optional which is nullable, except for the previous server in the ServerPostConnectEvent? 
because the previous server becomes the current one afaik
Fired after the player has connected to a server. The server the player is now connected to is available in Player.getCurrentServer(). 
I think the previous server is the server the player came from
seems like i cant send plugin message in ServerPreConnectEvent
works well if i don't send plugin message
message.txt by @hazy socket: https://paste.gg/4d1e856742ac44f898710b0bb3f54759
I mean, you're not connected yet
so you can't send a plugin message to the server
umm
i want to send to the server currently player is connected to
well player is connected to the server in ServerPreConnectEvent right?
As its name indicates, no, you're not yet connected. You're probs looking for ServerConnectedEvent. Iirc you will still need to wait a few ticks before you can send plugin messages
bump
umm i think i didn't explain it right.
i need to send plugin message to the previous server that player was connected to.
so my plugin is the previous server can fully save all data and THAN successfully keep connect to the target server
Ah, my bad. Anyways, sending a save request on player disconnect might be too late for the new server to get the fresh data. It's usually better to save the data on the backend server, and then send a server switch request to the proxy (e.g. using the BungeeCord plugin messaging API)
hmm what do you mean by 'backend sever'?
anyway the event is 'Pre' event so i thought it should work fine.
also delaying the event worked but that does not work
kindof sad
well my method worked in bungeecord but not in velocity right now
The backend server is Paper, Sponge, etc.
user -> proxy -> backend (essentially, if you want the technical terms most people use)
bumpx2
does this behavior replicate on waterfall/bungeecord?
if so, #paper-help (but my guess is you need to put a tick delay in the on join)
oh you're trying to handle tab lists on velocity? where did you get the API for that, afaik there's none built into velocity
You see it does work
Just like
For a fraction of a second
Then resets to default tablist entries
I think paper may be overriding it?
maybe, probably
put a delay, see if that fixes it ig
idk what API you're using to do scoreboards like that so I can't really help much, but that's my guess
0.o where, how
sure
package com.mattmx.ukmc.features.tab;
import com.mattmx.ukmc.UKMC;
import com.mattmx.ukmc.ingame.gamemanager.events.GameEvent;
import com.mattmx.ukmc.ingame.gamemanager.events.GameEvents;
import com.mattmx.ukmc.ingame.gamemanager.events.GameTabUpdateEvent;
import com.mattmx.ukmc.ingame.gamemanager.events.GameTablistUpdateEvent;
import com.mattmx.ukmc.util.Chat;
import com.mattmx.ukmc.util.Config;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.connection.DisconnectEvent;
import com.velocitypowered.api.event.player.ServerConnectedEvent;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.player.TabList;
import com.velocitypowered.api.proxy.player.TabListEntry;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import org.simpleyaml.configuration.file.FileConfiguration;
import java.util.Optional;
import java.util.UUID;
public class CustomPlayerlist {
@Subscribe
public void connect(ServerConnectedEvent event) {
update(event.getServer());
}
@Subscribe
public void disconnect(DisconnectEvent event) {
update(event.getPlayer().getCurrentServer().get().getServer());
}
public static void update(RegisteredServer server) {
FileConfiguration c = Config.DEFAULT;
for (Player playerToUpdate : UKMC.getServer().getAllPlayers()) {
GameTablistUpdateEvent event = new GameTablistUpdateEvent(playerToUpdate);
GameEvents.fire(event);
if (!event.isOverridden()) {
for (Player p : UKMC.getServer().getAllPlayers()) {
if (!playerToUpdate.getTabList().containsEntry(p.getUniqueId())) {
playerToUpdate.getTabList().addEntry(
TabListEntry.builder()
.displayName(Chat.color(c.getString("tab.default-list"), p))
.profile(p.getGameProfile())
.gameMode(0)
.tabList(playerToUpdate.getTabList())
.build()
);
}
}
}
}
}
}```
import com.velocitypowered.api.proxy.player.TabListEntry;
Can set the tab to whatever you want 🙏
oh it's scoreboards that aren't implemented, one sec, lemme look at it rq
@nova sparrow first issue - you're looping over all servers, but then you're looping over all players in the proxy never using that server variable, so it seems like you're doing a ton more work than you actually need to be doing to handle this
Oh i think that was me just messing around last night
Probably forgot to reset it to what it is mean to to be
can you show me a working example of it breaking, then I may be able to help more
also why are you doing it on join / disconnect when you're also setting up a scheduler to do it as well
are you trying to get a proxy-wide tablist? is that what this is meant to be doing
if it's per-server tablists why are you handling it at the proxy level
Wdym by that?
so your tablists are scoped to the server, so why are you handling the tablists at the proxy layer
like if 1 tab list belongs to a single server, shouldn't the server be handling that tablist?
I'd like to keep the formatting all syncronized
I think there's better ways to achieve what you're trying to achieve there, but okei, we'll go with it for now
It looks like you're effectively calling all players and managing each player's tablist on a scheduler with all other users, you're not really scoping it to the server, which you should be doing
for (Player playerToUpdate : UKMC.getServer().getAllPlayers()) {```
I imagine this should be replaced with the users on the specific server
Yeah it already is
and you probably want to get rid of the thing looping doing that since it's not really useful, nothing should really be pushing updates to existing users server-side, so you can probably get away with updating on-join
That code i provided was me messing with it
can you show me your currently working functions, so I can get a better idea of what you're doing
Working functions?
like what you're actually using
vs what you were playing around with
public class CustomPlayerlist {
@Subscribe
public void connect(ServerConnectedEvent event) {
//update(event.getPlayer(), event.getServer(), false);
update(event.getServer());
}
@Subscribe
public void disconnect(DisconnectEvent event) {
//update(event.getPlayer(), event.getPlayer().getCurrentServer().get().getServer(), true);
update(event.getPlayer().getCurrentServer().get().getServer());
}
public static void update(RegisteredServer server) {
FileConfiguration c = Config.DEFAULT;
for (Player playerToUpdate : server.getPlayersConnected()) {
GameTablistUpdateEvent event = new GameTablistUpdateEvent(playerToUpdate);
GameEvents.fire(event);
if (!event.isOverridden()) {
for (Player p : server.getPlayersConnected()) {
if (!playerToUpdate.getTabList().containsEntry(p.getUniqueId())) {
UKMC.getServer().getScheduler().buildTask(UKMC.get(), () -> {
playerToUpdate.getTabList().addEntry(
TabListEntry.builder()
.displayName(Chat.color(c.getString("tab.default-list"), p))
.profile(p.getGameProfile())
.gameMode(0)
.tabList(playerToUpdate.getTabList())
.build()
);
}).delay(100L, TimeUnit.MILLISECONDS).schedule();
}
}
}
}
}
}```
Okay it kind of works?
However
When i log on; already logged on players are not updated for the joiing account
Wait
might have it
OK
WE got it
Working
🙏
@oblique haven Thank you so much for the time and help
and priority sorted 😌
What version of the API should I depend on? The docs seem rather outdated
I see 3.1.0-SNAPSHOT and 4.0.0-SNAPSHOT on the maven repo
im gonna fly with 3.1.0-SNAPSHOT
how does one do configurations
i heard someone mention Sponge but im still confused
4.0.0 is barely even there
yeah so for configurations
it is recommended that you use Configurate by Sponge
ight
since it’s bundled
are there any example implementations
you can probably find some but there’s tutorials on their github page as well
can you link
yeah i just didnt know how to work with it in velocity
i tried looking into some other plugins but none of them seem similar
@Subscribe
public void loadConfig(final @NotNull ProxyInitializeEvent proxyInitializeEvent) {
this.configurationLoader = YAMLConfigurationLoader.builder()
.setPath(Paths.get(pluginFolder.toString(), "config.yml"))
.build();
try {
configurationRoot = this.configurationLoader.load();
} catch (IOException exception) {
exception.printStackTrace();
}
}```
this is what I have so far
but how do i do defaults
?
sponge has a discord if you want to ask configurate questions
do they? can you link to it
the class is there
im dumb then, i prefer Yaml
praise yaml
well i know what you are explaining, but the server switch will not only excuted by my plugin so i cant use that..
I’m open to have a PreServerDisconnectEvent (as a sort of last-call)
But that event would obviously only be called until after the next server is in Post-connect and also only if the disconnect wasn’t a kick or crash
The issue is Velocity waits for the new server connection to be successful and only then disconnects the user from the original server
This ensures the new connection can be aborted at the very last moment and the user won’t be kicked
That is partially the reason Bungeecord has these weird disconnects with some plugins that fire off multiple switch requests rapidly
lads
why does serverconnectedevent not fire after a player gets kicked?
i tried with serverpostconnectevent and it doesn't work either
context: i'm trying to make a reliable global chat plugin with server switch messages. when a player gets kicked from a server back to the lobby, my plugin doesn't receive the lobby's connect event
i shall keep investigating but if someone has any ideas please @ me
to achieve a "server switch" i'm listening to connection events that have a previous server (!getPreviousServer.isEmpty()) so perhaps getting kicked means that the previous server isn't set?
If the server they’re connecting to was the original server but that connection failed this will not be set
Otherwise I don’t think I’m following you
sorry, i think i don't quite understand it myself hence my poor explanation
i can try to explain it better, hold on
is it really ok to ask extensive stuff in this channel? i don't want to bother anyone or come off as annoying, but as a dev i like to write proper steps to reproduce stuff.
anyways,
after carefully looking at events while interacting with minecraft, i've collected this. i will use numbers to explain the player actions and letters to explain the related events, sorted by time. my plugin's messages will be between parenthesis.
working, expected behaviour:
1) player joins the velocity proxy
a) LoginEvent (chat plugin shows "player joined")
b) ServerPreConnectEvent
2) player joins "lobby"
c) ServerConnectedEvent (chat plugin doesn't show server switch, because event.getPreviousServer.isEmpty(): true)
d) ServerPostConnectEvent
e) CommandExecuteEvent: /server survival
f) ServerPreConnectEvent
3) player moves to the "survival" minecraft server
f) ServerConnectedEvent (chat plugin shows "player moved to survival" because getPreviousServer.isEmpty(): false)
g) ServerPostConnectEvent
[after this point, events are different from the next list]
h) CommandExecuteEvent: /server lobby
i) ServerPreConnectEvent
4) player joins "lobby" minecraft server
j) ServerConnectedEvent (chat plugin shows "player moved to lobby" because getPreviousServer.isEmpty(): false)
k) ServerPostConnectEvent
5) player leaves the velocity proxy
l) DisconnectEvent (chat plugin shows "player quit")
unexpected behaviour:
1) player joins the velocity proxy
a) LoginEvent (chat plugin shows "player joined")
b) ServerPreConnectEvent
2) player joins "lobby" minecraft server
c) ServerConnectedEvent
d) ServerPostConnectEvent
e) CommandExecuteEvent: /server survival
f) ServerPreConnectEvent
3) player moves to the "survival" minecraft server
f) ServerConnectedEvent (chat plugin shows "player moved to survival")
g) ServerPostConnectEvent
[up to this point, everything is similar to the previous list]
4) player gets kicked from "survival"
h) KickedFromServerEvent
i) ServerPreConnectEvent
5) player joins "lobby"
j) ServerConnectedEvent (chat plugin doesn't do anything, , because event.getPreviousServer.isEmpty(): true which is not expected)
k) ServerPostConnectEvent
6) player leaves the velocity proxy
l) DisconnectEvent (chat plugin shows "player quit")
as you can see, when a player manually moves between servers the events fire as one would expect, but when they get kicked the ServerConnectedEvent doesn't have the previous server's information
thus, as seen in step (j) in the second list, a plugin can't know where a player was kicked from
(please let me know if this is not ok so i can delete the massive wall of messages)
I understand your confusion, however, the previous server is only set on PostConnect because, including the ServerConnectedEvent, the connection can still be aborted
That makes little sense looking at it from the outside
indeed 😅
i will look at postconnect stuff then. thanks for guiding me (and sorry again for the huge message)
I appreciate the detail. As I said today already we are open for a set of Server disconnect events, which may help with this
If anything, this can serve as a guide for other developers. Thanks 😊
A flowchart for connect/disconnect events could be a good idea
Any way to set a players inventory, specifically like give them items
Not using built-in methods
That would require velocity to track player inventories among other things, which isn’t stuff a proxy should handle
❤️ cat
if by give items you mean, actually giving items, no
if you mean like fake inventories, no, but, teeechnically there are plugins which let you mess with packets, but, really, let the server do it, use plugin messages to talk
Plug-in messages? is that like an internal communication between velocity servers and registered ones?
don't mention
but, basically, yes
takes advantage of the custom payload packets in vanilla to send data over a players connection
How would i send a packet to a registered server (and vice versa if possible)
Like, what would i call and provide, i get the concept but im not sure how to execute it
Hello, everyone! I`am making a velocity plugin for paid passes for servers but I need send a Russian symbols but i have an <Sorry, I don`t know how name that, check image>
It's called the plugin messaging API, you can check Velocity's and your backend server's javadocs for more info
Thank you very much I'll make sure to check it out
Please, help me!
I have the following problem
Ah multi module project with a paper, velocity and common module. To be able to use adventure in commons i added the dependency as compileOnly I have other dependencies in commons as well which i added as implementation. So i used shadow to relocate them. Now i want to use a method in my velocity module. That is from a class in the common module. This method returns a adventure component. But velocity can't use it since it looks at the shaded location for the commons shaded location. Not the one that comes with velocity. So what do i need to change in the build.gradle.kts so i can use the adventure components in the commons module and that stuff in the velocity/paper module=
add the java-library plugin to common, change compileOnly to compileOnlyApi & implementation to api in common for everything you want to expose to users of the common module
you dont need to shade adventure if you're working on paper+velocity
oh missed that important part. Don't shade or relocate adventure
- don't shade/relocate any
compileOnly[Api]dep
I thought compileOnly does not get shaded by default 
is there a way to have the maven version of the module be the plugin version
I can't filter the .java file
filter the plugin.yml, then I'm a moron, this is the velocity channel<plugin instance>.getDescription().getVersion()
velocity
I'm a moron
minecraft supports unicode characters just fine (as you can see in the same image) so you're probably doing something wrong with encoding in your files. stick to utf8 generally
Quick question:
As some might've experienced, with incorrect encoding, a § can result in Â. After not facing that problem since 2018 or so, I'm currently facing it again. A config value says &cSomething.
In the plugin, I feed it into LegacyComponentSerializer but replace the & with § before (&([0-9a-flmnokr])) so both work.
It is in bright red, but there's an extra Â.
how? O_o
can i write a velocity-plugin.json manually
i see that the annotation is retained until runtime
does it check the type of the plugin?
probs because your compiling with the wrong encoding
You can, but it's not officially supported. Are you having some trouble with the annotation processor?
I don't see why gradle(7.2) would use something other than UTF-8. Especially on Linux.
But that's possible, the only § is in that class. I'll take a look later
#velocity-help, make sure you're connecting to the proxy and not to the server
ok
velocity CommandExecuteEvent isnt being called at all
can someone help me?
when i execute simple commands the event isnt fired
depends on what the command was intended for? Server? Registered command on proxy?
proxy
the command is executed on hub
but the command event never gets fired no matter what
i'm almost firing it myself lol
Mm, will take a look at this. Mind opening an issue on GH with version details and a small reproducer?
I don’t see any way it could happen. Feel free to open an issue, don’t have the time atm
indeed (decompiler)
dracula theme
plugin?
I love velocity!
We love you too!
Probably MaterialUI. Or Material UI lite.
That's what a lot of people use with IntelliJ
Is getting plugins in CurrentServer() possible
what
For example getting essentials api in a velocity plugin
Or, a way to get a players essentials DisplayName rather than using their Player Name
No
No
suppose I theoretically wanted to do some sketchy shit and inject into velocity's netty channel
playerConnection.getChannel().pipeline().addBefore(Connections.MINECRAFT_ENCODER, "MY_HANDLER", new MyCustomHandler());
``` would hypothetically do the trick, right?
basically I just have to hack the handshake packet's hostname field on the proxy->backend side. Maybe there's a better way.
Well... I can do some disgusting reflection to get at the hostname field of the vhost object's InetSocketAddressHolder. Really really disgusting but probably less disgusting than hijacking the netty pipeline
make sure to wash your hands
I did, three times
There really needs to be an event like riiight here https://github.com/PaperMC/Velocity/blob/340e1b23d60f507f9b09ea4fe0e8a7689df5fca5/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java#L183
I don’t see any legitimate uses for that so no.
You do realize velocity supports login plugin messaging? If you just need to add data onto the login process then you could just use that
Well given you don’t use legacy versions that is of course
Unfortunately it has to be done in the handshake packet because I also need to hijack it for status requests.
This also sorta happens as a MITM type of thing where this data I’m injecting is read (and stripped) before the server even has a chance to see it, so anything that happens after encryption is also off the table
It’s a really weird use case but really the only spot this is doable or even remotely simple is by messing with the hostname sent between velocity and the backend server in the handshake
What event would I use to get the player disconnection from a server,
if it doesnt exist, using DisconnectedEvent am I able to get the server wherer the player was or I'll have to cache that?
From a server its KickedFromServerEvent, that has a method to get the server the player was kicked/disconnected from
DisconnectEvent is for when the player disconnects from the proxy entirely
in that case you should first check for the login status and if correct check if current server is present, and you can get it from there
Just one thing, there's "ServerConnectedEvent"
It has .getPreviousServer
If a player is kicked from another server, is ServerConnectedEvent called?
No, KickedFromServerEvent is called, and that event decides wether to kick the player from the proxy or redirect them
If the player is kicked from the proxy the DisconnectEvent will be called?
What I meant by ServerConnectedEvent is, if a player is kicked from one server, like a prison server, and he goes to a lobby, ServerConnectedEvent will be called right? as the player connects to lobby
in that regard yes.
yes.
Thank you so much!
The better question is - what are you trying to do exactly
There’s probably a better way
Is there a convenient list of libraries Velocity includes, that way I don't need to include them in the Jar?
What event should I use for when a player joins the proxy, but with a listener that could take a bit to execute? (querying mongo) Just asking cause I saw in the javadocs for some of the *login events that I should "try to limit the work done in any event that fires during the login process"
If you need the data present to make a decision during login you need to block any of those events
Just if you do it too long the client will time out is what the comment about limiting work means
Ah, gotcha. I wouldn't need to block the login process at all, merely just updating some values in the players document on join. So I assume PlayerChooseInitialServerEvent would do just fine?
Events that leave the player dangling (not fully initialized or in transition) shouldn’t be blocked for more than 2 sec at max
You can fire off your own query thread or future from any of those events however
That won’t block the event and eventually you’ll have the data
Just creating a thread in the event wouldn't block it? I've never used futures, but am vaguely familiar with threads.
I said convenient
Is there a way to intercept a specific packet and potentially stop it from being sent to the player?
I want to do seemless world transitions by handling them myself. This includes intercepting the respawn packet
You’re better off doing that with bungeecord. Bungeecord is designed with intercepting things in mind while velocity is not
You’re basically trying to break all proxy logic here on velocity
It’s seriously easier to do on bungeecord
Plus you don’t need to reinvent entity ID rewriting
And all packets you probably need are there already
Ooof, that sucks because all of our existing codebase is on velocity, is there maybe a velo lib that could help with this?
Moving to bungeecord just isnt ideal due to time constraints is all
use a bungeecord proxy behind a velocity proxy
Velocity is designed around being a clean proxy
The issue is deeper if you want seamless switches:
You need to do the following:
Full tab-list rewriting
Full entity ID rewriting for all entities
Full dimension sync or rewriting
Full tracking of player state and effects
Full tracking of all active attributes
Full tracking and rewriting of all inventory IDs and windows
Only then will you have a usable seamless integration
And this puts a tremendous amount of extra load on the proxy
Velocity is fundamentally made to not have any of this
Why would those need a rewrite? Don't you just not send the respawn packet and handle chunk unloading/loading yourself?
No
because the players entity ID wil change across servers
and, so, any entities which refer to your player will have a different ID to what the client has without resending the ID or rewriting the metadata, etc
No; The new server will use IDs that overlap
And well that causes graphical glitches at the least
velocity works on the fact that you can reset the clients state in-play
bungee/waterfall (by default) works on rewriting a lot of crud to ensure that stuff works
noting that that mechanism has caused many janky issues over the years
(and creates much more work for the proxy as Five already stated)
I should mention that I am using Minestom and not a spigot fork btw
doesn't change much
That doesn’t change how the game works fundamentally
the client is still a stateful thing
if you get into entities, etc, you start needing to deal with the caveats of not resetting the clients state
You’ll also need to rewrite map IDs I just remembered
as for how far you need to go for your specific usecase to pretend it all works, etc
Wouldnt you just despawn the entities that are in the old dimension?
Map IDs aren't an issue for my usecase, only one of my servers will ever use maps
That’s not enough
What other caveats are there?
Read all that five said
a good % of bungees codebase is literally dealing with all the crud to keep the client happy across server transfers
once again, entities refer to other entities for various things using IDs
I am just struggling to understand where the issues lie, is despawning an entity not enough?
when you transfer across servers, your player ID will change on the server given the new entities, etc, etc
No
because it's not the entities themselves which are the issue
you just get lots of lighting glitches, ghost blocks and entities, buggy tab-list and scoreboard, blocks refuse to break, other entities get desynced
Potion effects stay in limbo
You can’t see nether portals
Fire doesn’t render
… and lots of other fun things
it's how they o things like referring to other entities
The entire game works off using the entity ID which is a runtime number which is incremented on new entity
We didn’t make those rules
That’s just how the client works
that entity ID is solely how the game refers to your entity over the network
And it varies wildly with versions
Yea I understand, I appreciate your guys' help with this
bungeecord, by not doing the set, needs to rewrite every single entity metadata packet to ensure that it rewrites any entity IDs which refer to your player to the entity ID that you where given by the first server
(as well as tryna avoid cases where your clients entity ID is the same as some other entity on the server, etc)
Aren't those just sent when you go to a new server anyhow?
There is a plugin out there if I remember the name right it was something like Full-sync that does the rewriting and mapping on the server
But it was for spigot exclusively iirc
That would probably be a good place to start
You literally have to disable the mechanism which lets you do that for the "smooth" transitions
which is what we're saying here
velocity relies on the fact that you can resend the entity ID to the client by resetting its state more or less
That's confusing, you're saying that velocity intercepts and stops entity meta being sent to the client when it joins a new server?
Velocity uses a trick to reset the client to after it has just logged in
That trick works ever since 1.7.2
when you join a server, you get a login packet which tells you your entity ID, etc
with velocity, or waterfall with entity metadata rewriting disabled, when you switch server, it sends you a new login packet
that login packet gives you your new entity ID, and by virtue of the clients code causes a lot of state info it has stored to be dropped
bungeecord, on the other hand, doesn't do that
Does a login packet trigger the loading screen?
yes
in orer to get rid of the login screen, you'd need to get rid of the login packet
getting rid of the login packet would prevent the client going into a state which is aligned with the server itself
On older versions velocity will not only send a join game packet but also one or two Respawn packets so the dimension is correct
Newer versions of the game have a lot more important things in the join game packet
which, bungee doesn't do the login packet, so bungee has a whole mess of code dedicated to rewriting the metadata of entities and trying to butcher other state to line up
I know three incorrect rewrites bungeecord does but I don’t care anymore because md_5 refuses to believe any of them
If arrows or tridents ever glitch out on bungeecord that’s the reason

(if it wasn't for the fact I can't be arsed, disabling metadata rewriting woulda been the default in waterfall for what, 2, 3 years now?
Does velocity forward the first game join packet exactly as it is sent by the first server the player joins?
Because I can ensure that the packets I use are the exact same with the same entity ID if so
It sends a customized one based on the server response
alrighty
If we re-sent the original it’d defeat the purpose of having the data from the new server
That can be especially important on 1.17+
Reason: minecraft 1.17 and newer doesn’t use world IDs but names to refer to dimensions
So if you don’t have a dimension the server wants to send you to…..
Bungeecord errors on this currently
But again md_5 doesn’t seem to care a whole lot
All my servers have the exact same dimension and the exact same namespace for it
I feel that we've kinda come around full circle into you not understanding the implications of it all
Again you can probably make this work for your use with some difficulty
If you need packet interception on velocity you can see how viaversion injects by replacing the channel initializer
But all I can say is that it’s gonna be a royal pain to do
And please don’t follow the bungee examples
Well what I understand is that the entity ID for the player can change between servers, which means that the client needs to reset to that new ID somehow
which you can't do without sending the login packet which resets the clients state which shows the loading screen.
because it can cause a ton of different issues
yea
You can’t reset entity IDs if you don’t re-send join game
there is literally 0 way to change the clients entity ID outside of that
which
leads you back towards bungees BS
which, isn't just rewriting an entity ID
It's rewriting literally every entity ID sent over the network
Or alternatively, I can sync my entity ids across the whole network
So that every player gets their own id
But anyhow I'll just have to compromise somehow, thanks for all the advice
It helps a ton
That’s what that plugin I talked about did
Well that and you have to ensure to never re-use old IDs which have been used on previous servers for entities != the player
Also to note
You’ll be responsible for:
Setting player:
inventory, position, facing, potion effects, velocity, abilities, gamemode, boss-bar, tab list, scoreboard and objectives, stop sound, despawning entities if within range (… and so on)
Also absolutely not working without a loading screen:
brigadier commands resync (tab-complete command list)
Map-tracking
Hardcore hearts (enable or disable)
Ability to select-click blocks using creative menu (certain newer versions work)
Ability to use hotbar to teleport to other players in spectator mode (without server modifications)
Also careful: if you re-assign the same ID upon a real Respawn you will likely crash the client
Thanks for the tips
Oh also: don’t forget to set the correct daytime
And if this matters: adventure mode will break entirely
If you need it you’ll have to hack in a feedback rewriter on the server
That may be different in newer versions but last I dealt with this I’ve nearly lost my mind
Wait why can't you resync the brigadier commands?
Also I think the solution for me will be to just use one server, I can separate logic between worlds
@Subscribe
public void playerChooseInitialServer(PlayerChooseInitialServerEvent event) {
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
try {
// Do long logic here
} catch (Exception exception) {
this.logger.error(exception.getMessage());
}
});
}
Is that the proper way to use a future? It works exactly as I'd expect and doesn't block the event, but am just curious if there's a better way I should be doing it
hi there is a way to change server brand? velocity --> custom
There is no supported way to do this. You’ll have to modify the source code of the proxy to do it, or make a plugin that hacks that part of the proxy logic. We don’t support it because it’s one of the few places where credit is shown to the software authors and contributors
I don't want to delete the Velocity writing but to modify it and unify it to the network style while keeping the software credits
I would like to ask if possible I have where to go to modify this writing to do what I have described above
Just git clone the repo, and search the string in the code maybe
but the word Velocity is kind of cool so i keep it
I think he just wants to add color
Five explained how you do it
for (RegisteredServer server : myplugin.getProxy().getAllServers()) {
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeUTF(arguments[0]);
out.writeUTF(arguments[1]);
server.sendPluginMessage(myplugin.getChannel("mychannel"), out.toByteArray());
}
This for loop should execute "lp user ..." in every Bukkit server however the rank is given successfully only in proxy and in server where I am
can't send a message to a server without players in it
Any solution to that or nope?
basically, you'd need to cache it and wait till somebody logs in
why wouldn't you just use luckperms with one backend db
ideally you just cross link everything properly and access the LP api directly
it has fine cross-server/proxy support
hi, i'm trying to make a whitelist plugin for velocity, but i dont really understand how to use brigadiercommand. i want to make a main command /vwhitelist which has a second argument which is a subcommand, but i don't know if i'm going in the right direction
this is what i have so far: https://share.boba.best/hdns05yy.java
nvm i figured it out
will any api be provided in the future to work with packets and, for example, add own "sessions" at the entrance?
given that packets aren't API, and there are many dozen nuances there, probably not
Please specify what you’re tying to do?
On one server, I saw authorization implemented using packets on BungeeCord. I was interested in repeating this on Velocity. Like BungeeCord, Velocity needs a protocol hack. Perhaps you could provide some more advanced API for this things. At the moment it does not carry any overly important purpose, just for interest.
no idea what you mean
you can already replace the url that the proxy uses for authentication
Yea we still don’t have a clue what you want to do
For that see the launch flags pinned to this channel
I'm not talking about Mojang authorization. With the help of packets, I ask the client to load world. After which, the client thinks that it appeared on a normal server, but it is not. Here I can carry out, for example, my authorization without using an additional bukkit server.
oh, limbo server, basically
yea, there is probs 0 interest on the side of velocity to implement all of the stuff needed for that type of thing
Ah. You’re talking about a full server simulation for an “auth” plugin for users that pirated the game. No, that won’t ever be supported. We don’t support piracy.
idea is to be lightweight and maintainable, not add a bunch of crud like adding support for writing world data and basically simulating a world
A proxy shouldn’t ever do any of this regardless
Let's look at it from the other side. I want to provide my players (ofc online players) with additional protection, or, for example, upload my resource pack.
Authorization as an example. I don't say anything about supporting offline players.
velocity would have to maintain support for writing stuff like level data, etc, chunks, and potentially all that other crud
from every version, 1.7+
Just, no
it's a proxy, it proxies, use a limbo server or something lightweight
Regardless of why you’d want to do that, it’s possible to hack in with a plugin. With that in mind, a lightweight limbo server is still always a better option
There is no class called SimpleCommand or RawCommand
Oh wait
Im unsure because someone said that the doc i was using was outdated
1.0.0-SNAPSHOT Does not seem like the latest
that would be an old api version, yes
~~Hey, I'm registering commands on Velocity using proxyServer.getCommandManager().register() and they work when I execute the command on the Proxy's console but not for players on each server, I believe I saw somewhere that you need to forward commands to each server so I was wondering how to do that?
Thank you.~~
Issue was due to not having the correct permissions, use LuckPerms-Velocity to set permissions to the command for yourself.
you need to make sure they have permission
if it's just for debug just return true in that hasPermission check
if not use a legit permission provider and use permissions based on those
LuckPerms has a velocity version
I was "fixing" a plugin I made for a client about 3-4 months ago, they just didn't have the correct permissions set 🤦
But yeah you're completely right, LuckPerms and such works just fine. I was just asking about forwarding because I looked up the issue in the discord and saw a staff member mentioning something about forwarding so I was wondering if Velocity made some weird change that I had to implement, thank you so much though.
😉 glad I could help
commands from the proxy never forward to the backend server
it just intercepts the declare and inserts its own stuff
bro they had luckperms installed already, just didn't set perms for themselves 😭

I don't think I've ever forwarded a proxy command to a backend server, wouldn't even know where to start on that lol
@oblique havenDo you need the HasPermission function?
I don’t think it’s required
Sorry for being nitpicky (heh), BrigadierCommands can forward conditionally if you return https://jd.velocitypowered.com/3.0.0/com/velocitypowered/api/command/BrigadierCommand.html#FORWARD from their executor
Apart from that you're right
Huh weird I get this error:
[13:15:41 ERROR]: Unable to load plugin plugins\DSVelocity.jar
com.velocitypowered.api.plugin.InvalidPluginException: Did not find a valid velocity-plugin.json.```
Using maven for this project.
How do I connect a player to another server
From a command
How do you get a player instance from a SimpleCommand
instanceof & Cast
How do you get Optional<Player> to Player?
If you know the optional is not empty, get.
How do I make that suggest function in SimpleCommand returns: first argument(all players), second argument(all servers)
Edit: solved, it's described here https://docs.velocitypowered.com/en/latest/developers/command-api.html#creating-a-simple-tab-complete
I need to check if it is a player from their args, should I do Optional<Player> == null or Optional<Player>().get() == null
