#velocity-dev
164 messages · Page 13 of 1
go watch a java tutorial on writing in a cooldown using a basic executor, then you can use that knowledge to make one (potentially) with velocity's built-in scheduler
that's a pretty normal system which should have a good amount of stuff on it - but it also takes time to write so people probably won't walk you through it manually
I find a method but it's not working
well what's not working about it - can you give us more info, maybe some stuff you've tried
we can probably point you in the right direction
public class Cooldown {
private final HashMap<Player, Long> cooldowns = new Hashmap<>();
private void add(Player p, long timeInMillis) {
coldowns.put(p, System.currentMillis() + timeInMillis);
}
private boolean isOnCooldown(Player p) {
return cooldowns.get(p) != null && cooldowns.get(p) <= System.currentMillis();
}
}
Idea 
globalised cooldown thing
@Override
public void execute(Invocation invocation) {
this.cooldowns = new HashMap<String, Long>();
okay
if (this.cooldowns.containsKey(executor.getUsername())) {
long secondsLeft = this.cooldowns.get(executor.getUsername()) / 1000L + COOLDOWN_TIMER - System.currentTimeMillis() / 1000L;
if (secondsLeft > 0L) {
executor.sendMessage(Component.text(traductColour(String.valueOf(secondsLeft)).toString()));
return;
}
}
genuinely terrible idea
and something you could do yourself if you wanted to do the terrible idea
in what universe is caching authentication a good idea
that... is not.. ok
whatever
"house" do you know anything about shared ips
vpns are not the only thing that use shared ips
you'd block schools, flats, dorms, most isps
ok what about the three other things i mentioned
an entire ISP could have thousands of randos sharing the same public IP
ah yes "security through hoping people don't know other people"
otherwise known as "let's hope people don't bruteforce usernames"?
I'm sorry but having a subdomain with alphabet soup is not a captcha
can somehow i put maven version inside a velocity plugin?
since the Version is put inside the soruce files than resources
Is there any reason why velocity's stable version is 3.1.1?
It doesn't support 1.18.2
because people got busy and theres still pending stuff to do before we can release .2
[19:12:00 ERROR] [axovelocity]: Error occurred while attempting to connect to Database.
[19:12:00 ERROR]: java.sql.SQLException: No suitable driver found for jdbc:mysql://ip:port/database?useSSL=false
[19:12:00 ERROR]: at java.sql/java.sql.DriverManager.getConnection(DriverManager.java:706)
[19:12:00 ERROR]: at java.sql/java.sql.DriverManager.getConnection(DriverManager.java:229)
[19:12:00 ERROR]: at net.axolotlhub.axovelocity.sql.MySQL.connect(MySQL.java:22)
[19:12:00 ERROR]: at net.axolotlhub.axovelocity.Main.onProxyInitialization(Main.java:69)
[19:12:00 ERROR]: at net.axolotlhub.axovelocity.Lmbda$1.execute(Unknown Source)
[19:12:00 ERROR]: at com.velocitypowered.proxy.event.UntargetedEventHandler$VoidHandler.lambda$buildHandler$0(UntargetedEventHandler.java:47)
[19:12:00 ERROR]: at com.velocitypowered.proxy.event.VelocityEventManager.fire(VelocityEventManager.java:598)
[19:12:00 ERROR]: at com.velocitypowered.proxy.event.VelocityEventManager.lambda$fire$5(VelocityEventManager.java:479)
[19:12:00 ERROR]: at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
[19:12:00 ERROR]: at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
[19:12:00 ERROR]: at java.base/java.lang.Thread.run(Thread.java:833)
I'm trying to hook up my velocity plugin to a MySQL database, anyone know how I can fix this?
Compile you driver with your build tool
So a shaded jar?
Yes
Already doing that
Yes, you can. You would use the templating-maven-plugin as follows:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>templating-maven-plugin</artifactId>
<version>1.0.0</version>
<executions>
<execution>
<id>add-plugin-info</id>
<goals>
<goal>filter-sources</goal>
</goals>
</execution>
</executions>
</plugin>
Then create a class in src/main/java-templates and define a public static final String VERSION = "${project.version}"; constant inside it. You may then reference this constant in your @Plugin annotation.
The templating-maven-plugin, it may be evident, will filter source files inside src/main/java-templates.
Try using Class.forName on the MySQL driver class; plugin-related classloading is infamous for its relation with service loading.
If you decide to use HikariCP, then I recommend using the data source instead of the driver.
Please ping me profligately if you have further questions.
So add the line Class.forName("com.mysql.jdbc.Driver");?
Yes. (Relocation will handle changing the classname string)
Alright, I'll give it a try
Same error, would my code be helpful?
Look inside your plugin jar - open it up with an archive tool. Make sure the MySQL driver classes are present.
I don't think it is present, there is no java folder (java.sql)
The classes you will be shading begin with com.mysql, not java.sql
theres no folder called mysql inside the com folder
My bad, assuming you relocated correctly, the driver class will be in the relocated folder. For example, com.yourpackage.libs.mysql
No such folder exists
Wow thank you so much
I went with stupid approach that just make velocity-plugin.json manually
How can information be exchanged between the proxy and the server?
For example, the player did something on the server and I want to transfer this information to the proxy
while you have the player connected that way you can use plugin messaging, otherwise you’d need a message broker like rabbitmq or redis
Kyori also has a gradle plugin for this called blossom that I found useful!
java.lang.RuntimeException: Unable to create instance of interface net.kyori.adventure.text.Component. Registering an InstanceCreator or a TypeAdapter for this type, or adding a no-args constructor may fix this problem.
Trying to package a Component in to GSON causes this error. Is there a build in class or should I create a TypeAdapter?
GsonComponentSerializer
How would I include that in my current GSON.
Map<String, String> eventWrappingData = (Map<String, String>) GSON.fromJson(payload, Map.class);
there's a populator method that you can use on your gson builder
so like
var myBuilder = whatever;
myBuilder = GsonComponentSerializer.gson().populator.apply(myBuilder)
Thanks that is working, there doesn't happen to be a serializer for sound? It not erroring but it doesnt seem to be playing it. I am checking the data now
It looks like trying to convert sound results in it being null
Also I could've sworn paper natively supported adventure-platform. However looking through my maven packages I don't see that. Do I need to include it separately now?
There is no sound serializer no, hence why it's called ComponentSerializer
Paper does not and has never included adventure-platform - it natively implements the api, so things like Player implement Audience, thus making adventure-platform useless
Ok thanks, I couldn't find the correct sendMessage function as the remapped spigot jar was for some reason hiding it. But reordering the imports fixed that. So is there a way to serialize sounds of would I have to make my own serializer
why do you have the spigot jar in your classpath if you are using paper
and no, you'll have to make your own serialiser
for the remapped jar
I am currently unaware of a way to easily get the remapped jars without compiling paper. If there is something dumb I am missing I would love to know about it.
you are yes
also #paper-dev
are there any use cases differences between redis pubsub, rabbitmq and grpc for broadcasting database updates across minecraft server network running behind velocity (there may be multiple velocity proxies with the same set of backend servers)?
updates like
- party members list change
- game state changed (e.g. game started ⇒ should no longer send new players to this server)
etc.
@true chasm One last thing if you look into the repo again, in the velocity package, I am getting an unresolved reference @ compile("com.velocitypowered:velocity-api:3.1.1")
you probably want compileOnly
how can I serialize a component and then deserialize (im using velocity)
Also
Whats the best way to catch the players that get kicked
when the proxy shutdowns
I'm runing multi proxy and i have to fix the player count, .getAllPlayers returns empty on proxy shutdown
shouldnt the DisconnectEvent get called
Hello, I'm new on Velocity and I have two questions about plugin development:
- Velocity provides folder name in lower case for some reason when i use @DataDirectory injection (platform standard?).
- When I using logger provided by velocity injection log records from my plugin looks like this:
[01:06:01 INFO] [com.feniksovich.x.y.z.w]: <MESSAGE>
Instead of:
[01:06:01 INFO] [PluginName]: <MESSAGE>
Any ideas about #1 and fixes for #2?
Thanks in advance.
Is there a method to send change the player's currently connected server?
nvm i found it (createConnectionRequest)
I'm confused on how the async events work. For example, I've got a PlayerChooseInitialServerEvent and I want to modify the initial server but I have to do some async processing in order to determine what I want to set the initial server to. Is it as simple as this for example?
@Subscribe(order = PostOrder.EARLY)
public void onInitialConnect(PlayerChooseInitialServerEvent event, Continuation continuation) {
someFuture.thenAccept(targetServer-> {
event.setInitialServer(targetServer);
continuation.resume();
});
}```
did you give the docs a read? https://velocitypowered.com/wiki/developers/event-api/
Yeah I did
I understand the continuation is a callback to resume event execution but I'm not clear on what I can call and where
You can’t really do async processing on @\AwaitingEvent s
Reason is that if you end up waiting for the result to complete the event it is no longer async
Discord please

lmao
Alright what would be they way to do what I described? Or is there no way currently?
just run whatever you need to do and then set the result
Just make sure it doesn’t take longer than 3 sec
😄
The client can get disconnected with a timed out message
can or will?
We don’t know to be exact. Modded clients allow a much longer wait time
and just not connect them if it takes longer
Thanks though!
@fossil sundial But can I still run that continuation stuff though?
@Subscribe(order = PostOrder.EARLY)
public void onInitialConnect(PlayerChooseInitialServerEvent event, Continuation continuation) {
someFuture.thenAccept(targetServer-> {
event.setInitialServer(targetServer);
continuation.resume();
});
}``` Like I feel like this is valid or I'm still not understanding
since its async, the initial server it set async later when the future completes then event execution is resumed
Or does that continuation stuff only mean the next events are run once that continuation is complete
That’s not what happens.
If you do that you end up setting a value on an event that’s already complete
oh I see
That’s why I said if you need data you can’t be async
gotcha
So I think I'm still missing the reason for events being async
@Subscribe(order = PostOrder.EARLY)
public void onLogin(LoginEvent event, Continuation continuation) {
doSomeAsyncProcessing().addListener(continuation::resume, continuation::resumeWithException);
}```
Like this is from the docs, I dont really see the idea of it

got me wondering what the point of these async events are
Because either you're on the network thread or you're not
idea of async is so that you're not clocking the networking thread
The wiki says. " The event system allows a plugin to pause sending an event to every listener, perform some unit of computation or I/O asynchronously, and then resume processing the event". Specifically the "then resume processing of the event" makes me feel like it will not process the event fully until the continuation is resumed
hm, am not really sure how the continuations work, tbqh
From this message it seems like 'thats not what happens' but I cant think of any other use for it
Looks like maybe you need to return the continuation?
For an annotation-based listener, all that is needed to process an event asynchronously is to either return an EventTask or add a second Continuation parameter
oh
hm
Like, the logic does look like it's supposed to do that
Anyone know who wrote it? 😄
was backported from the polymer branch
I don't see where that is even handled, however
yeah idk about u but I cant think of a reason to give the implementer a continuation to resume without letting them handle execution
If anyone knows the workings of these async events besides being processed on another thread please lmk, it'd be very helpful
Hey, trying to modify this plugin a bit.
Over at line 113 on https://github.com/Erisfiregamer1/PistonQueue/blob/main/src/main/java/net/pistonmaster/pistonqueue/shared/PistonQueuePlugin.java the plugin checks if the server is online and if so set a var to true
How do I make it so it does that after a successful ping?
Help?
I mean, we can't really do a deep-dive on the source for random plugins to give you an answer
iirc, there is a method on the server info thingy or maybe RegisteredServer to ping the server, ping it and see if you get a response
If you need unconditional asynchronous execution for all events of a certain type, you can set the async attribute on the @Subscribe annotation (see https://github.com/PaperMC/Velocity/pull/384/files#diff-815fdc6d02e26aaee3fe4d2992d3765be1c0e456b05e5d5838aed15774882bf6R34). As electroniccat said, an event can have conditional asynchronous execution (e.g. migrate threads mid-execution) by returning an EventTask. In this case, the most useful impl is EventTask.WithContinuation. Then, the event manager will wait until you resume the continuation to call the remaining handlers (see https://github.com/PaperMC/Velocity/pull/384/files#diff-d8ddbbf479b18d6b2c4bebc809feb8fb37dd0f305c79bf84aed7e534091f1b0aR423 for details). Do note that the event task need not be async and it can block the Netty thread; I wouldn't recommend this unless the computation is trivial. A complete example (ignore the formatting, am on mobile):
@Subscribe
EventTask onMyEvent(MyEvent event) {
// Do something on Netty thread (probably, see technicality below)
return EventTask.asyncWithContinuation(continuation -> {
// Running on a separate thread pool, you can do expensive stuff here. This lambda is called by the event manager after the handler (the onMyEvent method) returns the EventTask containing it.
// You can mutate the event here. The object is received by future handlers; thread-safety is guaranteed by the event manager.
event.setProperty("bar");
// Notify the event manager the asynchronous computation is complete. This is needed since e.g. we could create a new thread in this lambda and let it resume the continuation itself, without needing to join it.
continuation.resume();
});
}
The doc states that it can have the 2nd param as a Contination
but, I dont think that's even hooked in the current release
For your case, however, using EventTask.async is simpler and cleaner; continuations are useful for more complex thread coordination. Thus, the code above is equivalent to
@Subscribe
EventTask onMyEvent(MyEvent event) {
// This *can* be run on the Netty thread.
return EventTask.async(() -> /* This runs on a separate thread */ event.setProperty("bar"));
}
I've never used it that way /shrug
Technicality: a handler that's not marked async may be run on an async thread. This can occur e.g. to the remaining handlers after a handler returned an asynchronous event task.
If I may be permitted, allow me to explain the motivation behind all this:
The objective of asynchronous listeners is to improve efficiency by reducing thread jumps (called context switching). Before async listeners, here is what would happen:
- Velocity encounters some event
- The event manager fires the event on another thread
- Every listener performs its computations on this separate thread
If Velocity needed the results of the event, it would then resume relevant operations after the completion of step #3. So, on the whole, Velocity fires an event, the listeners perform computations on a separate thread, then Velocity resumes relevant operations if applicable.
A context switch occurs between #1 and #2 when we switch threads. With async listeners we intend to reduce the preponderance of context switching. An async listener is rather a listener which has control over its own thread context. An async listener can request to always use another thread or it can always use the same thread; it can dynamically switch threads too, if it wishes.
Supposing all our listeners to be async listeners:
- Velocity encounters some event
- The event manager calls the first listener.
- When the EventTask from the first listener is complete, the event manager calls the second listener.
- When the EventTask from the second listener is complete, the event manager calls the third listener.
...
Once all listeners are complete, Velocity resumes relevant operations. The use of EventTask delegates control over context switching to the async listener. (However, note that in the current implementation, one listener cannot determine the thread context of the next listener).
Is ServerResourcePackSendEvent appeared in 3.1.2 version?
Yes. Since 3.1.2 is still not 100% done it’s not in the changelog yet
ty
Is there a way to cancel (denied) ServerResourcePackSendEvent and not send DECLINED status to downstream server?
No. Why would you do that? That’s an invalid protocol state
I'm trying to make plugin that prevents resource pack double-installation for the players already installed resource pack once.
It useful for servers where resource pack applies on backed server (downstream, in lobby server for example).
If a player switches server and then returns to the lobby again, they will have to wait for the resource pack installation process again, since the server/client doesn't check that such a resource pack is already installed.
That’s what the hash is for. If you set it then that won’t happen. There was a bug for that afaik- we fixed it by comparing the hash of the currently applied resource pack to the one being sent
Otherwise we have to assume you’re actually updating the pack
Let me quickly see if that’s what we did
Turns out I did never implement that fix, just had it in mind, my bad. Please open an issue on GitHub
You’ll have to wait till the 25th for me to implement it though
Unless someone else is quicker
Okay, it would be really nice if this was implemented at the proxy server core level 👍
@oblique haven if you wanna grab that free PR
In the backend play session handler
Check if the currently applied pack has the same hash and if yes return true and send a success downstream
Since we provide api for it and this is an unforeseen bug we can easily fix that’s fine to do
One thing to consider here
If there’s a pending pack how would we handle that
Don’t have the mental capacity for that atm
This fix would only work if all servers provide the hash
You can still make a fix plugin that calculates and adds the request to resource pack requests from the server on the proxy in the meantime
That will also fix it
As far as I know, most admins use plugins to send resource packs that generate hashes automatically. So this shouldn't be a problem.
You can still make a fix plugin that calculates and adds the request to resource pack requests from the server on the proxy in the meantime
Good idea
Thank you Five for quickly support
What is a pending pack?
A pending pack is when the client has gotten a pack but has not sent denied or success yet
I don't quite understand why this would be a problem.
According to my implementation for BungeeCord, I simply store a map with UUID and resourcepack hash.
If the player's UUID wasn't there, I wait for the client to send a packet with the SUCCESSFULLY_LOADED status to add it to the map.
I wait for a packet from the server, which will send resource pack installation request to the player again. If the received and stored hashes match for this player, then I simply cancel it and send a packet to the downstream with the SUCCESSFULLY_LOADED status.
Maybe I'm missing something 
That’s basically what velocity should be doing in a nutshell
Alright so I was told I cant mutate the event async, was that a mistake or am I misinterpreting. Again, the goal is to do an async request to get a server to set to the initial server of a connecting player (regardless of the fact that the client needs this response within 3 seconds apparently)
@Subscribe(order = PostOrder.EARLY, async = true)
public void onInitialConnect(PlayerChooseInitialServerEvent event) {
EventTask.asyncWithContinuation((continuation) -> {
someFuture.thenAccept(targetServer-> {
event.setInitialServer(targetServer);
continuation.resume();
});
})
}```
Can in a bit
You can mutate the event; let's prove it: your event handler is called here https://github.com/PaperMC/Velocity/blob/e8bf6ab5222d8bbf4e59e7c4d5400b10ab4c7e81/proxy/src/main/java/com/velocitypowered/proxy/event/VelocityEventManager.java#L598. Assume you return an EventTask. Then, the ContinuationTask below is executed, after receiving the event object. Also assume your plugin resumes the continuation. Then Velocity executes the next handler here https://github.com/PaperMC/Velocity/blob/e8bf6ab5222d8bbf4e59e7c4d5400b10ab4c7e81/proxy/src/main/java/com/velocitypowered/proxy/event/VelocityEventManager.java#L583. Note that it is passed the same event object. When the last handler resumes its continuation, the future is completed with that event object https://github.com/PaperMC/Velocity/blob/e8bf6ab5222d8bbf4e59e7c4d5400b10ab4c7e81/proxy/src/main/java/com/velocitypowered/proxy/event/VelocityEventManager.java#L577
Thanks this makes more sense now, not sure what Five was talkin about earlier
No problem 😜
If anyone wants to add this/the previous message to the wiki, feel free. Too busy rn to do it myself
What I was saying is that it doesn’t matter if you use a continuation or just block the event itself; it leads to the same result
It’s not async
And it can’t be because it’s linked or chained
huh
you sayin I can block for my futures in that event and just block whatever thread is running that event and potentially others?
what specifically isnt
Is there anything in the api that allows me to grab the players on a specific server ?
The amount of players
in a singular instance, you'd basically just check get the players which are on that registered server
So for instance a "hub" plugin with the selector, I'd want to get the players on {minigames}.
declaration: package: com.velocitypowered.api.proxy, interface: ProxyServer
If it's an unknown server name I'd do what electronic said, probably loop through all players online or just keep that info stored and ++ -- when someone joins/leaves
Is t possible to set the uuid of a player? On bungee you do it with the PreLogin event
package index
No
I cant find anything there
thats why i ask
im not as dumb as other people that dont know java docs
otherwise i wouldnt ask here
declaration: package: com.velocitypowered.api.proxy, interface: Player
My question is not send me the jd link
my question is
Is it possible to set the uuid of a player
Does Velocity support dem fancy books?
no
why not
because velocity would have to keep track of inventory state is which feasible
why so
to open a book you give the user a book and then tell them to open it and then remove the book, putting back what was there before
The player game profile request event allows you to do that
But be warned; this will break on 1.19.1 and newer
@opaque escarp ^ the client will essentially kick itself if it cant verify signatures it sent
Hello
It's possible disable this message [connected player] PLAYERNAME (/example:11111) has disconnected
How do I send a Player to a RegisteredServer
Player#createConnectionRequest
and then call connect or fireAndForget or whatever your use case is
how do you get the max player limit of a server or check if it's full
ping it
ofc, that won't account for perms which allow players to join when the server is full, so best you can generally do is to just try joining unless you wanna aim to fully respect the reported limit
If you have ViaVersion, use latest dev build
i think i had this problem bc my encoding wasnt utf 8 or maybe it was smthn else idk
How does Velocity check whether a plugin "appears to be Bukkit/Bungeecord", I'm trying to make a library and I do have plugin.yml and bungee.yml in the resources, but also a @Plugin annotation on the correct class
It checks for those after it didn’t find a velocity-plugin.json
You didn’t correctly configure the annotation processor if your build environment didn’t generate one for you
Is Velocitys API thread safe?
Anyone here knows what can cause this error?
Yes
Except for things you aren't supposed to mutate concurrently in multiple threads (e.g. event objects)
how do i execute a velocity command via chat-clickEvent
Right I forgot the annotation processor, though can I just create the velocity-plugin.json myself or is the annotation processor also used for something else?
nothing special, just Component.text("click me").clickEvent(ClickEvent.runCommand("/hi")
Tried that ;) but it says that the command is unknown. It seems to work for bukkit commands only
(as a player i can execute the velocity command btw.)
try without the /
that's definitely not it
all that click event does is make the player run that command, if you can also run it as a player then it works
well, command unknown would be not registered or no perms
hence proxy/bukkit doesn't matter, the player is the one running the command so it'll go through both
if it runs asthe player themselves, that excludes that
How to recieve a plugin message?
didn't 1.19 add some kind of thing where you no longer need the / before the clickevent? Because they don't allow sending chat messages anymore
no, now it's required
all we can see there is that the connection to the server was closed in an unexpected manner
Seems to be happening without the plugin too, strange.
Ah it's another plugin doing it.
If compression is disabled on the server and enabled on the proxy, velocity itself will compress traffic?
Yes, it's better to set compression -1 on backend spigot servers, and the default compression of 256 on velocity, so the packets are compressed only one time when they reached the proxy
Compression = more cpu usage and less bandwith usage
So if you are on a local connexion (most of the time proxy <-> spigot) it's better to disable it since you have "infinite" bandwith
OK, thank you
Hey, anyone know how to check if a player is opped? Thanks!
pretty sure there's an isOp method
Wrong channel
I meet the same problem as yours too
how can I make idea ignore that fields annotated with @Inject are never assigned?
alt+enter, press right arrow on warning, press suppress for things annotated with inject
yes, I tried this, but there was no thing related to "suppress annotated with inject"
I added <writeAnnotations> tag to .idea/misc.xml and it worked
You can otherwise use the constructor
So you don't need to @inject on the attribute
Hello.
While player logging in,
I want to store the player's Client brand into database.
but Inside the PostLoginEvent
the getClientBrand() seems to return null (but if I do it in a commnad, it works (maybe I need a slightly delay or something))
Any solution?
@Subscribe
public void PostLoginEvent(PostLoginEvent e) {
Player player = e.getPlayer();
System.out.println(player.getClientBrand());
declaration: package: com.velocitypowered.api.event.player, class: PlayerClientBrandEvent
yea I just discovered it mins ago
Thank you
if you have the google code plugin installed in IJ it shouldn’t show that
what is it called? I can't find it
I don't know what you want to do but brand name is clientside, so it can be easily spoofed, and most of the time it will return "vanilla" except for some clients that implement it
for example Lunar Client will show as "lunarclient:version" but Badlion Client will show as "vanilla"
Velocity does offer the ability to communicate with the client using login plugin messaging which, when combined with the other api should allow to identify any client that wants to be identified
but you’re right
its about the intention to be identified
thanks
is there any way to remove (Velocity) thing that is always added after client/server brand names?
or to customize modification pattern if there is one
no supported way, removing attribution is cringe
is there a way to create a command that shows a GUI to player in velocity?
velocity does not have inv support so, within the realms of the api, no it's not possible
You can use protocolize
which isn’t supported fyi
Bug in velocity: When client sends plugin messages right after receiving login success packet, and the backend server isn't in play state. An error.
What should happen, Velocity queues the packet to later be sent when the backend server switches to play state
Already know about it- the entire play handler is due for a rework
We need quite a few queues
Ah good. I have gotten a couple of issues that this is the cause
The play handler is going to be a compound handler in the near future
Aka not a single class
I’d rather construct a handler from what’s needed for plugins to work
We were here before when clients sent commands before a server connection is established
That’s very stupid but can happen
That’s also incorrect
I know this may sound stupid
But I’d rather not queue messages if possible
This may include delaying login success until a connection is established for the first time
The API a doesn’t guarantee a lot of continuity
Yea, whatever is best solution
I can reply to the guy that he should use a faster connection to the backend server
And that there is a fix coming soon
Hey, is there a way to send player to another server from backend server level or would I need some kind of agent running on velocity + message queue?
Something like https://www.spigotmc.org/wiki/bukkit-bungee-plugin-messaging-channel/#connectother basically 🙂
oh, okay, I though there's some dedicated way of doing that velocity-style. Thanks 🙂
How can I communicate with the proxy server from any of its sub-servers?
Lemme explain
so I have 2 servers running on the proxy and those servers contain plugins
I would like to know how to get the server name that is configured in proxy.toml of the subserver the plugin is on
also how can I communicate with them using a class? can a class be loaded on all servers if I load it from a proxy plugin?
classes are not magically shared across JVMs
and you can use plugin messages for communicating, assuming you have a player
hmm
it makes sense about JVMs but no its not about a player
its about getting a subserver's proxy name from a plugin on the subserver
not sure how thats done
Server.getName() does not give the name configured in velocity.toml
Basically
as I literally said
You can use plugin messages
BUT, you need a player connected to do that
otherwise, there is literally no means to get that info magically, you'd need to pass it in manually
it's a mechanism for sending custom data between, generally, a server and a client
but, the proxy being a proxy can sit in the middle and also (ab)use that feature
i see
i've thought of a way i wanted to ask about not sure if its the best way to do that since i have no idea how to use plugin messages
using redis
basically onProxyInitilization i will bind all server names to their port key (port), value (name) to the redis database
and when i am on the subserver's plugin i would use redis to get the name of the server from its port
is this possible or am i wasting my time?
does velocity shade mojang authlib?
No. We don’t need it. The very few things we need don’t warrant it
then should I shade it in my plugin myself if I need it as a universal class for several platforms (including velocity, paper, etc)?
What do you need the authlib for?
I don’t see any usage that requires the full feature set
A few lines of code are usually enough to replace it
only for GameProfile class
using the whole authlib for a single class isn't a good idea ig then
yes, but as I said before, my plugin is for multiple platforms
You should use what’s provided by the platform. Mojang is strict in their api limits for querying profile data
A few wrapper classes are probably a better idea- since you’ll be converting from each platform anyway
How do I make Text URL e.g. 'discord.gg/papermc' a clickable URL in velocity?
thanks man
In order for plugin messages channels to work do in need to register them like how they are done in bungeecord?
yes
if its legacy channel should i put legacy:channelname
think so
i just registered the channels but they seem not fire event when i send the plugin message from minecraft server
There’s the legacy channel identifier
Legacy channels are for 1.12.2 or lower, but 1.13+ it needs namespace,MinecraftChannelIdentifier as i did everything as expected, cant get the event to fire
isn’t it just ChannelIdentifier
ChannelIdentifier is an interface
declaration: package: com.velocitypowered.api.proxy.messages, interface: ChannelIdentifier
ah yeah mb
@fossil sundial idk if we have proofs or PRs for it yet, but here's my POC for a chat queue:
https://paste.gg/p/anonymous/70600b540e4e4845921d7d6a011ab599
works completely asynchronously
and we can even use this for timestamp validation if we want to do that - we just have to implement it into that since it already keeps records
then we need to port timestamps to specific packets - so like in the piggyBack function we'd have some mapper of (priorTS, EnteredPacket) -> NewPacket or something like that
let me write up a PR to incorporate this into the chat building functionality
Hi anyone uses specific development environment i mean libraries and testing enviroments some frameworks or something
https://github.com/CoreyShupe/Velocity/commit/e4f57c362fd93007d3a6a7cc12ddcd1df8d58faa feel free to look through and let me know what y'all think
I mean it's specific for what you want to do
@weary moth here's your impl, still unsure if anyone has attempted
very unintrusive and should have the least amount of discrepancies with what's trying to touch it, going to run a bunch of testing with it tonight to see if I can get it to send out of order crap
i mean i want to start project with full testing env and want to know what other people use
you can use smth like Junit
I use JUnit/AssertJ and this is how I have it organized in case it serves as an example using the Velocity API https://github.com/4drian3d/KickRedirect/tree/main/src/test/java/me/dreamerzero/kickredirect
Few hours of trying to find until i saw that i forgot adding '@Subscribe' after realizing issue, i had temptation to destroy my computer 🫠
Velocity supports forwarding information about your players to your servers, such as IP addresses, UUIDs and skins.
are these the only things velocity forwards?
velocity forwards primarily the Ip and the UUID
the UUID thing is used in part for allowing the server to fetch skins (as well as identify players properly)
How Do I listen to the received plugin message in Velocity?
I have this in spigot plugin and it works fine
messenger.registerIncomingPluginChannel(this, "FML|HS", (s, player, bytes) -> {
String result = (new String(bytes, StandardCharsets.UTF_8)).substring(1);
System.out.println(result);
});
But in the velocity, it doesn't work at all.
@Subscribe
public void dwdw(PluginMessageEvent e) {
System.out.println(e.getData());
}
Did you register the listener and event handler?
See this if you need an example
Yes I did
Basically I sent these to the player
player.sendPluginMessage(new LegacyChannelIdentifier("FML|HS"), new byte[]{-2, 0});
player.sendPluginMessage(new LegacyChannelIdentifier("FML|HS"), new byte[]{0, 2, 0, 0, 0, 0});
player.sendPluginMessage(new LegacyChannelIdentifier("FML|HS"), new byte[]{2, 0, 0, 0, 0});
Did you register the channel
public static ChannelIdentifier FMLHS = new LegacyChannelIdentifier("FML|HS");
@Subscribe
public void onProxyInitialization(ProxyInitializeEvent event) {
server.getChannelRegistrar().register(FMLHS);
// register other stuffs...
}
@Subscribe
public void PlayerClientBrandEvent(PlayerClientBrandEvent e) {
Player player = e.getPlayer();
player.sendPluginMessage(FMLHS, new byte[]{-2, 0});
player.sendPluginMessage(FMLHS, new byte[]{0, 2, 0, 0, 0, 0});
player.sendPluginMessage(FMLHS, new byte[]{2, 0, 0, 0, 0});
}
@Subscribe
public void PluginMessageEvent(PluginMessageEvent e) {
System.out.println(e.getData());
}
the PluginMessageEvent doesn't work
But in Spigot, it reads response successfully
messenger.registerIncomingPluginChannel(this, "FML|HS", (s, player, bytes) -> {
String result = (new String(bytes, StandardCharsets.UTF_8)).substring(1);
System.out.println(result);
});
nope I think the client already receive the plugin message
since I can read response from spigot
and isn't this for bungee and spigot
no its is for spigot
if you are sending to proxy
you have reigster it as outgoing
i send plugin message from Velocity to Player
And Player response to Server -> I can't read response from Velocity but Spigot can.
Is there a possibility that because It's Forge's Mod List stuff
So the PluginMessageEvent is not firing
And I checked PlayerModInfoEvent aswell, It doesn't fire too
When I use this to get the users locale it always prints out en_US. When I change my language it stays the same. When I do the exact same thing on the paper side it works perfectly. Does anyone know what I have done wrong?
And the Method player.getEffectiveLocale() returns null every time. My problem is that I need to get the player locale when the player joins the network.
I use the 'ServerConnectedEvent' Event.

you dont need to use a decompiler
you have to wait for the https://jd.papermc.io/velocity/3.0.0/com/velocitypowered/api/event/player/PlayerSettingsChangedEvent.html to fire at least once
declaration: package: com.velocitypowered.api.event.player, class: PlayerSettingsChangedEvent
Probably he does not have the enviorment to run the software, but yeah well github exists

Ah okay thank you. 👍
yea the locale is one of those things that will only be asserted by the client after a connection is already in the PLAY phase past the server connection events
you can set a custom default locale value with the setEffective…
but until then you dont know
Okay. 🙂 But is the PlayerSettingsChangeEvent fired before the Player establishes a connection with the paper instance? Because I want to get the Player Locale for a default language.
no- it is fired after a server connection is already established
thats why I said in PLAY phase
the timing there is tight so we cant exactly change that behavior
its just how the client works
Yeah I understand. I will find a way to use it right.
is there any alternative to Bukkit.getMinecraftVersion() on Velocity?
Depends- Velocity supports any version from 1.7+
You can get the protocol version of a player with
declaration: package: com.velocitypowered.api.proxy, interface: InboundConnection
how can I get the latest version supported by Velocity?
or latest protocol version
declaration: package: com.velocitypowered.api.network, enum: ProtocolVersion
^ That + https://jd.papermc.io/velocity/3.0.0/com/velocitypowered/api/network/ProtocolVersion.html#getMostRecentSupportedVersion() will get you the string for the newest version
declaration: package: com.velocitypowered.api.network, enum: ProtocolVersion
yes, I see, thanks
not really a velocity dev question, but I get in a velocity plugin, so
what may be the cause of me getting NoSuchMethodError here? the method is here and the same signature :/
[15:10:20 INFO]: dataFolder = /home/user/velocity/plugins/cloud-api
[15:10:20 ERROR]: Couldn't pass ProxyInitializeEvent to cloud-api
java.lang.NoSuchMethodError: 'void org.yaml.snakeyaml.DumperOptions.setIndentWithIndicator(boolean)'
at org.simpleyaml.configuration.implementation.snakeyaml.SnakeYamlImplementation.configure(SnakeYamlImplementation.java:182) ~[?:?]
at org.simpleyaml.configuration.file.YamlConfiguration.setImplementation(YamlConfiguration.java:62) ~[?:?]
at org.simpleyaml.configuration.file.YamlConfiguration.<init>(YamlConfiguration.java:52) ~[?:?]
at org.simpleyaml.configuration.file.YamlConfiguration.<init>(YamlConfiguration.java:43) ~[?:?]
at org.simpleyaml.configuration.file.YamlConfiguration.<init>(YamlConfiguration.java:33) ~[?:?]
at org.simpleyaml.configuration.file.YamlConfiguration.load(YamlConfiguration.java:403) ~[?:?]
at org.simpleyaml.configuration.file.YamlConfiguration.loadConfiguration(YamlConfiguration.java:174) ~[?:?]
at <...>.loadConfiguration(<...>.java:85) ~[?:?]
at <...>.onEnable(<...>.java:50) ~[?:?]
at <...>.onProxyInitialization(<...>.java:47) ~[?:?]
at <...>.Lmbda$1.execute(Unknown Source) ~[?:?]
at com.velocitypowered.proxy.event.UntargetedEventHandler$VoidHandler.lambda$buildHandler$0(UntargetedEventHandler.java:47) ~[velocity-3.1.2-SNAPSHOT-153.jar:3.1.2-SNAPSHOT (git-74edac96-b153)]
at com.velocitypowered.proxy.event.VelocityEventManager.fire(VelocityEventManager.java:598) ~[velocity-3.1.2-SNAPSHOT-153.jar:3.1.2-SNAPSHOT (git-74edac96-b153)]
at com.velocitypowered.proxy.event.VelocityEventManager.lambda$fire$5(VelocityEventManager.java:479) ~[velocity-3.1.2-SNAPSHOT-153.jar:3.1.2-SNAPSHOT (git-74edac96-b153)]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) ~[?:?]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) ~[?:?]
at java.lang.Thread.run(Thread.java:833) [?:?]
That method doesn't exist in the JVM, there may be a version mismatch between your dependencies and the version the server has?
yea, version mismatch
that class is shaded into my plugin's jar
one really should relocate their own deps
hmm, lemme try
Hello guys
i need any help
Can you someone help me?
but
i not found ip forwarding in velocity
that worked, thx
forwarding-mode = "legacy"
Is there a simple way to translate all colour codes of a line ?
you can use a serializer like minimessage
All I can say is that confuses me a whole lot more
For § or & see the adventure legacy component serializer
How should i load resources from plugin jar?
Like
getClass().getResourceAsStream("resource.txt");
``` - this is not working
try using the classloader
use getClass().getClassLoader().getResourceAsStream("Name");
is there any configuration api provided with velocity? If so can someone link me to the docs for that
nvm figured it out
Please never ever answer to yourself with just
nvm figured it out
Always add a link / something that you found so that others searching through this channel / seeing you message can know how you got it to work / where the docs are / ...
private ConfigurationNode config;
private void loadConfig() throws Throwable {
configFile = new File(getPluginDataFolder(), "config.conf");
if (!configFile.exists()) {
InputStream is = getClass().getClassLoader().getResourceAsStream("config.conf");
if (is == null) throw new NullPointerException("Missing resource config.conf");
Files.copy(is, configFile.toPath());
}
HoconConfigurationLoader loader = HoconConfigurationLoader.builder().setFile(configFile).build();
config = loader.load();
}```
Can Velocity register new server at "hot"? I saw that is possible with bungee core... I would like to create a command which add a new server to the proxy with the pterodactyl API.
yeah, via ProxyServer#registerServer
is it safe to do blocking operations in LoginEvent handler?
As long as they don’t take over 3 seconds
The client has a hard limit of seven seconds to complete login
Quick question: is there any official maven repos for the latest builds of velocity-proxy? I can't seem to find it anywhere official.
The papermc maven repo has it. Sorry the old site really needs updating
Wait
-proxy?
That’s not meant to be published
Only the -api part
Keep in mind that the API is licensed MIT
But the proxy parts are licensed GPL
We don’t officially support plugins that use the -proxy package
well that's annoying. I guess my plugin won't be able to support velocity then .-.
Well that's for the clarification anyway.
thanks*
You’re free to suggest api additions if they’re sensible. There’s very little that I could see needing direct access to internals
(Except stuff proxies shouldn’t be doing like inventories)
I understand that I can access it but i was really hoping for a good way to implement it in a sensible way.
But yes, the reason I need access to the internals is because the two events I saw that could access commands didn't handle commands client <-> proxy <-> server
only from the client <-> proxy
Wdym
Proxy plugins have full control over commands processed by velocity
Exg the command execute event is also fired if the command is meant for the server instead of the proxy
Well the issue I'm having is that both CommandExecuteEvent and PlayerAvailableCommandsEvent didn't fire when there was a command sent from client <-> minecraft-server
or when a Commands packet was sent from minecraft-server <-> client
respectively
The only direction command packets are sent is client > proxy/server
And I couldn't find an event for that in velocity
well yes, i understand that i'm simply trying to illustrate the problem.
If the commandexecuteevent is not fired then the command was issued by a plugin using executeImmediately
But there’s no other case where that happens
I don’t think I broke that
i suppose it also wouldn't fire if the server executed a command as a player
is EventTask.withContinuation for deferring event results?
Fair
I think you misunderstand. I want to be able to intercept when a client runs /somecommand(tm) irrelevant if the command is registered on the proxy or is being forwarded to the server
but like, getting -proxy in your classpath wouldn't help you with that situation anyway
so,,, the command execute event?
It would
Yea and that event should allow that
Hmm
In the case of @ AwaitingEvents it doesn’t matter
Well i'll give it a shot again. Perhaps i just goofed and din't register it or something stupid haha
no it wouldn't ... if a server executes a command as a player then the proxy isn't involved at all whatsoever
No, If i open my chat buffer and type /somecommand(tm) It will be sent from the client.
I want to intercept that.
And as i said, the events velocity has seem to only fire when the command is registered on the proxy.
and the event should be xallled for that
This means I can't intercept a command that isn't registered on the proxy.
have you debugged it?
Careful iirc velocity removes the / from commands found in that event
Yeah I had a logger open when my plugin processed the commands. I'll do the test again and see if it is any different.
Ok so good news, It seems something has changed between the stable/dev-builds and it's working on the latest dev build without needing to use packets!
Sorry for bothering :)
Oh nevermind, I see what I was going on about now.
So on legacy clients (pre brigadier/1.13) command completions would be sent when a user runs /<tab> The issue is I can't manage to get TabCompleteEvent to fire when I do this.
And yes, I am registering the event
It does, however work if I listen for the packets (no surprise there)
tabcompleteevent doesn’t fire for >1.13 clients iirc
I see, so the only solution here is packets?
Also, perhaps it should fire because /somecommand some-non-brigadier-completion is a valid use case for the latest version of minecraft. Otherwise there would be no way to detect it.
You also seem to be correct, even on a 1.19 bukkit server running /about E shows me completions for Essentials but no tab complete is fired.
well
there is an ask_server briagaider completion thing
the client completes /, from the command list sent to the client
but, /about E; should show completions if implemented properly
there's a seperate event for >1.13 afaik?
It didn't
yes, that works properly. But on <1.13 servers this is rewritten by VIAVersion as TabCompleteResponses for >1.12 clients
This basically breaks my plugin if the owner decides to run it on any server running VIA that is pre1.13 as it's only job is blocking commands.
ask_server is the only mechanism which fires tab completion which works on 1.13+
for 1.12 and before, you get to complete the entirety of /command
if you want to hide /command, you'd need to remove it from the list of commands sent to the player for 1.13+
The screenshot i just posted was from 1.19 on a 1.19 server
Here, i just double checked:
So, 2 second looks, the server on fires the tab complete event when the tab completion comes from the server
Yes, that is what i'm trying to modify
so, for example, if the above screenshot had Test Foo and Something I could remove a specific suggestion before forwarding it to the client.
This is very useful for servers who wish to de-clutter their commands when the plugins do not provide support to do it via permissions
One example of this is removing useless aliases like ehome in favor of home
oh, nvm, only fires if 1.12 and from the server
for 1.13 looks like you're just kinda screwed and would need to hijack packets
Well, I did get something working very well with packets. The only issue was that I couldn't find any official repos for velocity-proxy
well, updated ones at least.
we don't publish the impl to the maven repo, just the API
Remove them in the PlayerAvailableCommandsEvent
This event provides the player with the available suggestions. Unlike pre 1.13 this dataset is static unless the server wants to change that
That doesn't help with 1.12 servers running VIA or with 1.19 servers completing subcommands
and yes, i already do that.
You need to use both
I mean, you're gonna need to ^
Ah yeah, I see what you mean and I already do that.
for sub commands you're gonna have to look at the structure AND deal with the packetry back and forth of the tab completion
I know it’s inconvenient but that’s basically the only way to do it right since the implementation is so different
I already implemented that for both brigadier commands and pre-brigadier commands
well, not on velocity for the last one^^
I mean, for stuff on servers, this is really just best to deal with it on the server, as the server has all that context
I agree but people nagged me to make it compatible with bungee, then velocity.
And it did make sense at the time. One central config n what not.
well, yea, all is nice when you're not the one writin the code lol
I know right haha
I mean, I can't really see anything wrong with it
Another quick question: my logger is formatting itself with the fully qualified class name of the plugin rather than the plugins name. What is the correct way to fix this?
get one with the name of your plugin instead of the class, basically
I see (I was just using the one the wiki recommended)
Cheers
Still needs to be tested
I haven’t had the time
I tested specifically the chat queue by itself but haven’t tested my impl of it in velocity so I know the concept works and it also allows for spoofing, I will check both
I mean, I hate the overall thing
but, like
I don't really feel inclined to deal with the entire rip out I'd need to do for my solution
I mean what’s the better solution
If you explain it to me I’ll try to impl it for you so we can play with the idea
The completable future thing just seems the most sensible here since it allows for the future to handle itself when it’s done
I mean, my own solution was generally just using a raw queue without the futures and basically just having a queue to pop off once the event handler fired
I'm just semi mentally dead and wanna see how 1.19.1 will generally apply to some of this mess
basically, we need to make sure that in the event of a cancellation of the event, that we're able to send out the relevant header packets, etc
That seems much more complicated
For no reason
Having to fire from a queue complicates everything and makes us actually act on things, the only time we can ever know for certain that packets are in order is if we’re receiving them in order from the client
If we spoof one then we need to fit it into that order, the queue impl does the same thing with another stage for us to handle.
We’re already passing around futures everywhere, why not make use of their completion stages..?
The event handler has its own whole executor
I mean, I'm not 100% aware of how futures work internally and all that
also never said firing from a queue
Basically an object wait object notify
“Having a queue to pop”, that’s what I was referring to there sorry
I mean it effectively achieves the same thing I think
A precisely ordered queue which allows for outside entries into the ordered queue through piggybacking timestamps
that's redundant in 1.19.1
At least, with signed stuff, i think
So, shoving in our own custom stuff into that thing is not something I think that we need to care about
CPSH#710
That stuff was there for an exploit prevention
Player#sendMessage(Component.text("&4test message&etest message&1test message&2test message&3test message"));
The color disappeared in the new line
don't mangle legacy text into a component
that shouldn’t even work
either use components properly or use the serialiser... ^
what about unsigned commands? do they just sign all commands at 1.19.1?
well, we'd need to deal with the time deposition BS
generally it just seemed more viable to use plugin messages for chat + commands
the chat queue I implemented deals with that
just by the way
unsigned commands still send a timestamp
the unsigned commands time delta for handling along with chat's time delta for handling is handled with this queue
and any entries made during a handle will be assigned to the next available position (spoofed commands)
if all commands a signed this chat queue becomes very simple - but if commands remain unsigned we're going to need a queue which doesn't lose its place
yea, but I'm not exactly sure that this is a good solution long term
kinda relying on the fact that mojangs handling of that stuff is kinda shitty
well it's just assuming the client is sending to us in the correct order (which is already verified)
i.e. it's just stealing the last time and praying that mojang doesn't prevent that from being done in the future
well we could also just add a millisecond
if it's unsigned it doesn't matter
the only way to stop that is to just sign all of the commands
but I don't think that's their purpose
if we need to drop "stealing the last time" we can just drop the piggyBack method and it all works the same anyways
the queue doesn't rely on things being pushed into it to work - and it will still deal with time deltas across the command handler(s)/chat handler(s)
I don't think the solution I made is really "hacky" it just solves order between the client->server communication, and it will always work with signed information, so it's pretty future proof. Even if they remove timestamp hijacking, then it should be fine since it will cause earlier issues than that, and as I said before it'll still work in that case.
Its not hacky as much as it's just relies on somewhat janky logic in the server
which logic?
the part where mojang only cares about time going backwards
there's no logic in the queue
I mean, what else would they care about
they can't verify system time against player time
(oops sorry for pinging you like 3 times, didn't realize)
no, but they coulda and maybe shoulda verified that time went forwards
Then we can add a millisecond
Time will “go forwards”
I mean, sure, I guess
but that's somewhat part of why I wanted to just move that stuff over to using plugin message
I mean I’d wholly rather get velocity generic across servers and not require paper as a backend
I don’t like the idea of adding more stuff to plug-in messages to make it work when there’s better viable vanilla solutions
Forwarding makes sense, only way to do forwarding is through a custom session server or plug-in messages, but chat being there doesn’t make sense
I also think we should at least try to keep things at spec rather than re-implementing it
I do understand the plug-in message method though and do know it would be rather easy to do ^ but there’s just ways to do it without requiring backend impls so we should probably take it
I mean, we just make it part of the forwarding spec for velocity
and then if you wanna say that you're compat with velocity, you have to implement it
I mean, am just in a weird position where mojangs system has me iffy in general, especially as it's still a moving target
Yeah I get it
It just feels really restrictive to me
I think I like my solution better, I’ll throw it in a PR maybe later today and we can discuss in there other options
I think we should make a list of options and their actual raw benefits
Yea, I mean, it has the same general effect as mine, just, uses futures, which, futures are something which makes me iffy too lol
Haha
Futures are basically notify based stage handlers for an asynchronous process
I mean, they just get to be a bit of a clusterfuck to pick up what is going on, which is part of my iffyness for your thing is that it generally just looks kinda messy
I can clean it up 👍
Absolutely
Futures can be better understandable you just have to write it in a certain way which I can do
Honestly for this it’s probably all about formatting and adding comments
But we can push out a bunch into real functions
@bold wharf https://paste.gg/p/anonymous/a241bb2c07d54c57a6beb8444b016244 is this more understandable? I tried to break it out into parts rather than mushing it all together
do note, a future can have multiple whenComplete callers
public static void main(String[] args) {
CompletableFuture<String> future = new CompletableFuture<>();
future.whenComplete((string, throwable) -> {
System.out.println("When complete 1: " + string);
}).whenComplete((string, throwable) -> {
System.out.println("When complete 2: " + string);
}).whenComplete((string, throwable) -> {
System.out.println("When complete 3: " + string);
}).thenRun(() -> {
System.out.println("When run 1");
}).thenRun(() -> {
System.out.println("When run 2");
}).thenRun(() -> {
System.out.println("When run 3");
});
future.complete("test");
}``` for example this prints out everything listed, 1-3 for both, so we can chain appropriately
ik how futures work
okei
but, yea, that generally looks cleaner, for cancelled events do note that we will still need to broadcast some stuff out
broadcasting -> server? that's all that matters here
I'm only putting the chat queue in the ClientPlaySessionHandler
we should also move the validation of timestamp order into the chat queue, that way we can validate through the queue rather than having a held timestamp in the session - tracking previous timestamps aren't great but like, hijacking needs timestamps to use which are known
How would you feel about the move from:
future.thenApply(item -> new WrappedPacket(previous.timestamp, packetMapper.map(previous.timestamp, item)))
.exceptionally(throwable -> new WrappedPacket(previous.timestamp, null))
.whenCompleteAsync(writePacket(connection), connection.eventLoop())
.whenComplete((packet, throwable) -> awaitedFuture.complete(throwable != null ? null : packet));
```to:
```java
WrappedPacket.wrap(previous.timestamp, future.thenApply(item -> packetMapper.map(previous.timestamp, item)))
.whenCompleteAsync(writePacket(connection), connection.eventLoop())
.whenComplete((packet, throwable) -> awaitedFuture.complete(throwable != null ? null : packet));```
not sure which is cleaner
my one concern is chat plugins on the proxy, if they cancel packets and send them themselves
they'll have to interact with the chat queue
if someone is messing with internals, let them learn to mess with those internals
well, issue is that in 1.19.1, if somebody cancels chat packets, we still need to send information to all clients
really?
Yes
hm okay
why I can't override execute function in a class which implements com.velocitypowered.api.command.Command ?
well I mean that can be done in the process chat handler
that can be outside of the queue
You need to send a header packet in all of the clients involved
you can pass null to the queue and it will be fine with it
so we send null to the queue and send info to the clients
oh crap are we going to have to have knowledge of all the clients on the server
so, in .1, the chat works by basically storing a ref to the previous message to retain a "context"
makes sense
the client will keep iterating that and basically referencing the last chat packet it sent
and so, if a chat is cancelled, we still need to send out the header so that clients can keep track of the context
hm okay
so I wonder how we do that then
so with that we probably have to use the plugin channel to emit the header
but I don't think we need to verify they're on velocity, they can just ignore messages
we can just send something like velocity:chat_cancel_header and send the key ref to forward to the clients
hm?
} else if (signedChat != null) {
ByteBuf bufMessage = Unpooled.buffer(signedChat.getSignature().length);
bufMessage.writeBytes(signedChat.getSignature());
return new PluginMessage("velocity:cancel_chat_header", bufMessage);
}
return null;```
like this
then send the plugin message from proxy -> server
you said it's necessary to send the header
if cancelled on the proxy
there's no way for velocity to know all the players involved
this ofc creates many dozen issues
I mean we can block incoming client plugin messages if they're on velocity:
Like, on velocity if somebody "denies" the message, do we broadcast that from the proxy?
Like, technically, we should do that
but, technically, that is kinda gross
the proxy should never assume it knows about all the players on a specific connection
that's not a good idea
well, that's part of the issue
I'm thinking that we just find a way to delegate that over to the plugin
I don't see a sane way to handle this mess
so if a plugin is cancelling a chat event it is in charge of broadcasting the signature update?
wait
I'm confused now
okay nvm I think I got it now
so cancelling chat on the proxy should be a huge deal now and we should probably throw red flags and tell people to be careful
I think that letting people be in charge of the broadcast is fine if the paper api provides a way to do that cleanly
maybe paper should have a paper:update_chat_ref
Well, as said, chat messages now store a ref to the last chat message
if you cancel a chat message and don't send out the updated refs, the clients next message is going to refer to a chat message which doesn't exist to anybody, thus breaking that chain
so, now, if you cancel a chat packet from the server, or, proxy here, you now need to ensure that you send out the relevant information to clients to say "hey, heres the current ref from the client", that way the next chat message will still have a valid part of the chain
prepare to be blinded
specifically the "is player a recepient"
"is recpient" also really needs to extend towards cancellation on the server
but, the question here is how do we deal with this on the proxy too
Use one of its sub-interfaces, such as https://jd.papermc.io/velocity/3.0.0/com/velocitypowered/api/command/SimpleCommand.html
declaration: package: com.velocitypowered.api.command, interface: SimpleCommand
is this rocket science
not complex for paper developer
its not really complicated
probably you're right
@oblique haven the queue is good but two issues, it has to work for signed command components too and we also need to consider the signed suggestions

It does (it works for signed)
Signed command components will sign with their own time stamp, the only thing it modifies is unsigned
What are signed suggestions?
The queue is just a packet queue really, it ingests any packets and maintains their order with event handlers in the mix
That’s all it’s doing so we can stretch it for whatever we need
Here’s what I’m thinking
In (queue)
- linked (out) queue: Suggestions (decorator)
Required so we can verify signatures
I don’t think I understand
Can you explain how suggestions are apart of this
That’s the part I’m missing, and how they’re working
The decorator determines what’s signed. That’s why it needs to be a part of the queue
If no suggestion/decorator then a literal is signed
Hey guys!
Can you please tell me how can I control who will receive the message in the PlayerChatEvent?
or should I do ChatResult.denied() and then send the message myself to the players I need?
We will have api for that to accommodate 1.19 soon
Hi, may I ask does anyone have experience with HEX RGB? 
I'm working with Velocity for the first time and doing support for Velocity, but I don't know how to solve hex rgb on Velocity
If you're using Adventure components, apply a TextColor to your component (https://jd.adventure.kyori.net/api/4.11.0/net/kyori/adventure/text/Component.html#color(net.kyori.adventure.text.format.TextColor))
If you're using MiniMessage, see https://docs.adventure.kyori.net/minimessage/format.html#color
Is it possible to modify the logger? For example instead of "INFO" it says "DEBUG", I want to make a debug for my plugin and I have created a custom ConsoleHandler + Lombok but I can't modify that, I have to add after the name of my plugin "DEBUG" to know that it is the debug although at the beginning it says "INFO" and that's why I don't think it's the most appropriate thing.
Debug -> Info -> Warn -> Severe
If you try to use the "Config" which is really the debug I think, you won't be able to use the current bukkit logger
wut
So I have made a custom consoleHandler but I need that instead of INFO, I get DEBUG when I use the DEBUG. Because if I use the log.info I get INFO on the left, but if I use the log.fine for example I still get info too, and I don't know if it's possible to change that.
Are you talking about velocity dev ?
"INFO" I think this is the default level in bukkit and I don't know if it is possible to change it
oh sorry
I thought it was the paper-dev channel lmao
🤦♂️
Okay, I think we can use that impl for what you’re thinking of here
Since the class is just a packet queue we can have it go in and out either way
Is there a way to get the ProxyServer instance/a plugin instance from a static context?
I'm not aware of anyone else writing my own code, but ok
what I meant is having a way to get any plugin's instance without having an instance of the ProxyServer at hand, eg. on Bukkit: Bukkit.getPluginManager().getPlugin("myPlugin");
ProxyServer != Plugin instance
declaration: package: com.velocitypowered.api.plugin, interface: PluginManager
I specifically said I need to get a plugin's instance from a static context, which I obviously can't do with this method since I don't have the plugin manager's/the proxy server's instance from which I could get the plugin manager. Does velocity not have a way to do this then?
any documentation regarding toml and velocity?
What is your aim?
Does running a Scheduled task run the task on a separate thread?
Or multiple different threads, because I keep getting the feeling that code is being skipped or run in the wrong order ...
iirc tasks use a thread pool
is there a way to set the motd component colors to custom RGB colors?
Yes, use static factories from TextColor
ProxyPingEvent#setPing(ProxyPingEvent#getPing().asBuilder().description(MiniMessage.miniMessage().deserialize("<gradient:green:blue:#FF0F00>gradient motd").build())
@hard vortex
In the docs, there's written a hint:
Registering an object as a listener
server.getEventManager().register(plugin, listener);
In my IDE, this server variable isn't known. Any solution to this?
I got this currently:
public class MainClass {
@Inject
private Logger logger;
@Subscribe
public void onProxyInitialization(ProxyInitializeEvent event) {
server.getEventManager().register(plugin, new ListenerClass);
}
}
ah, nvm. one scroll further there's the explanation.. Sorry 😅
I'm trying to get a Player object but got ConnectedPlayer which class I dont have access (com.velocitypowered.proxy.connection.client.ConnectedPlayer)
got that result with this code
public class MyCommand implements SimpleCommand {
@Override
public void execute(Invocation invocation) {
CommandSource source = invocation.source();
System.out.println(source.getClass());
}
}
instanceof time ?
trying to learn velocity, I just want to get a Player object to develop some simple interactions using commands
what do u mean?
how much java do you know?
actually enough to develop some simple apps
about 6 months to 1 year of experience with java
I mean, I know what you are talking about
but I want a Player instance, but got ConnectedPlayer
class which dont is included in the api
But ConnectedPlayer implements Player
didnt found anything in the 3.0.0 docs
but if ConnectedPlayer implements Player, invocation instanceof Player should result in true?
in the case invocation.source()
just found why my code wasnt working properly
tnx
If you’re using java 17 you can do
if(invocation.source() instanceof Player player) {
player.disconnect(Component.text(“We don’t like players”);
}
(Aka typecast in the condition)
I think the old way is cleaner but its nice to know I can do it that way too
That’s precisely why it was introduced because creating and casting a variable in the next line is clutter
What is the velocity messaging channel name?
like when a spigot plugin is trying to send message through the channel like BungeeCord
to switch servers
same as bungee
unless you disabled it in the velocity config, the channel Bungeecord (on 1.12.2 and older) or bungeecord:main does the exact same on velocity as it would on bungeecord
no need to reinvent the wheel and enough plugins use it for us to just roll with it
I need to get the server instance to register listeners. I can't do this directly because I'm making an extension to a plugin that doesn't directly give me the velocity server instance. The plugin itself is quite extensive and refactoring it to give me the proxy instance would be almost impossible since the common module registers the extensions and the platform submodules don't have anything to do with the extensions.
every class can have an @Inject ‘ed proxy server instance. I still advise against it
I am having weird problem trying to solve, i have plugin messages being sent correctly in locally hosted environment but, some people are complaining that no data is being sent back, i found this is the case in friend server too, not sure how to debug this
Show your code?
I first did some logger info on event, does not seem to fire, but locally it does
Can you show your code
[16:54:19 INFO]: [initial connection] /IPHERE:PORT has disconnected: multiplayer.disconnect.missing_public_key
p i n s
are book packets possible in velocity?
packets? sure - but opening a book isn't available in the api at all
hmmm, ok, because the plugin protocolize has made it possible to open and intereact with guis and send other packets so i was wondering if i could do a similar thing with books
okok, thank you
hi how can I change this writing? thanks I await response (to your answer please tag me)
@agile ore ^
Hey have you guys encountered the problem that the DisconnectEvent event was not always firing?
It doesn’t fire if the connection blows up hard enough (can only be caused by a plugin blowing it up on the proxy itself)
Otherwise it should always fire
how can you get total players online a velocity network?
proxyServer.getAllPlayers().size()
Cleaner and faster, https://jd.papermc.io/velocity/3.0.0/com/velocitypowered/api/proxy/ProxyServer.html#getPlayerCount()
declaration: package: com.velocitypowered.api.proxy, interface: ProxyServer
i mean how can i change the proxy version name when example i view it on namemc.com ?? example how can i change the version name visible to users maybe a user enters with a version that velocity does not support but exits as this example thanks and awaiting answers
the server uses velocity)
ping event has a version method
yes how can i change the name like this server did?
by using the version method in the ping event
how do i can't do it can you kindly explain to me?
im not writing the code for you
there is a ping event, listen to it and modify the result to set the version string to something else
where do i find this ping event?
it's ProxyPingEvent irrc
would this be?
does that say ProxyPingEvent
ok there are and where can I change the writing that is
are you a developer
sorry for the pings)
ù
like a plugin developer
i am not a java developer or plugin
because in theory the developers should be able to "" explain this to me "
i literally did
in practice very few people have the will/time to teach java to everybody who wants to use this channel
- learn java
- learn velocity plugins
- listen to event
- change version
as I said, there is a plugin out there which probs fits your need in the other channel
After modifying the UUID using GameProfileRequestEvent#setGameProfile. The chat message signature will use the modified UUID or the original UUID. Does the client know its own UUID modification?
hi i am developing a plugin but it has a error that
com.velocitypowered.api.plugin.InvalidPluginException: Did not find a valid velocity-plugin.json.
i follow the doc and use kotlin for devlopment
In Gradle you must declare the annotation processor
use kapt
actually i did declare annotation processor
Kotlin uses kapt
well....what is kapt?
It's how you specify an annotation processor in kotlin
See their docs/look for projects on GitHub for an example, I don't remember the specifics
please contact minehut support for this before reaching out to velocity support
Minehut's velocity configuration is generally unsupported and should usually be vetted by us before reported to velocity, especially login issues like these
How to listen for plugin messages on velocity? both from the client's mods and the proxied servers
and if a client mod sends something over a plugin message channel that say bungeecord uses, could it be possible to hijack it and access unauthorized places? (such as a build server)
well, the bungeecord channel, no, because the proxy validates that the sender is a server and doesn't let it be sent to users
Yes however that will no longer work on 1.19.1 because the mojang UUID is part of the signature then
Changing the uuid then will just break signature
Is there a way to check the sender is a server? And how would I even go about receiving a plugin message from the first place? I can't seem to be able to find any documentation or examples of it being done
instanceof the source object
see the javadocs
I don't remember, either there was an event or some proper registration system
there was a gist somewhere with an example
Could you please fetch it for me? I can't seem to be able to find it..
No
Atleast I tried
I don't have a copy of it saved somewhere, maybe five or somebody does
I just used the saerch for register
pin?
Dumb question, but how do I get the Player object if the server sent the plugin message?
well, they would be the target
So e.g. Player player = (Player) event.getTarget(); ?
something like that
Cool
I’d get the player using the serverconnection https://jd.papermc.io/velocity/3.0.0/com/velocitypowered/api/proxy/ServerConnection.html#getPlayer()
declaration: package: com.velocitypowered.api.proxy, interface: ServerConnection
That’s the intended way
Therefore, the UUID of the client cannot be changed in 1.19.1. Is it because https://wiki.vg/Protocol#Login_Success has changed?
But I wonder if it's possible to do something like a UUID conversion (like NAT) that just spoofs the back-end server UUID. Does this break the chat signature?
No, the uuid is part of the key signature. If you change it anyway then other players and the server won’t be able to verify the signatures
Is there any change between 1.19.1 and 1.19, you said it no longer works on 1.19.1
Yea exactly that
server generate key for all clients, and re-signed all the message?
by definition of the system the key is private
It’s a lot more chaotic
if servers could resign that would defeat the point
what was the way other clients get others public key?
Tablist
so we just swap out the key in tablist and it should work?
sign(uuid+ public key)?
Key + UUID + Expiry date > Signature
Signed against Yggdrasil
Signature is generated by Yggdrasil
Not possible to spoof
we also swap out the signature too?
the entire point of the system is only the player can sign it. There's no way around it
oh i know private key for signature is hold by Yggdrasil
Yes
And a modified server
(And modified proxy)
I’m dreading writing the player key manager
Alas it has to be done
I just want to do one thing, I need players to load playerdata by my special uuid, I don't want to change the file name, because it will cause the pets in the world to not know the owner.
thank you all, i will find a solution
scoreboard API for velocity please
Will come with the intent system in 3.2.0
But that’s rather low on the list atm seeing how massive the 1.19.1 update is technically
How to use Command args with SimpleCommand?
Wait
Fr?
Well shit finally
The command context (the first parameter of the execute method) has an args method that returns an array of strings
Is there a documentation on creating configs and other resources? Pls ping with answer
For configuration files, see the Configurate wiki on GitHub
What do you mean by other resources?
idk some extra config.yml for menus or something

