#velocity-dev
164 messages · Page 12 of 1
you can find good docs on their github wiki
Hello, i can't deny the ChatResult with a message?
you could deny it and send the player a message
but afaik there's no "chat result" packet which even exists
That's what I did, but I find it strange that there is a method to accept with a message but not to refuse with a message lol
Thanks you !
right - this overrides what the player sent
Oh right, I misunderstood the method
i just created a fresh velocity project in intellij with the mc extension, why am i getting all of these errors?
this is what my pom looks like, this is a test plugin
try a build
message.txt by @real kelp: https://paste.gg/c64d7f496195443c958876ec677bd36c
[ERROR] Failed to execute goal on project me.bubbarob19: Could not resolve dependencies for project testvplugin:me.bubbarob19:jar:1.0-SNAPSHOT: Failure to find com.velocitypowered:velocity-api:jar:3.1.1 in https://repo1.maven.org/maven2 was cached in the local repository, resolution will not be reattempted until the update interval of central has elapsed or updates are forced -> [Help 1]
you have a dep which you don't have available
velocity version 3.1.1 doesn't seem to work
3.0.1 worked but idk how outdated that is
and then its all of these maven plugins that arent working properly
not sure how to fix any of this considering idk what any of it does lol
(your pom is also invalid, name shouldn't have a . inside of it)
ah it seems the repo they put in the mc intellij extension is outdated
ill see if i can update the plugin, thanks
yea, fixing the name and the repo and it builds
question: is there a license requirement when using the velocity-api to develop plugins?
or can I choose any license for my plugin
Most "standard" licenses will work, the API is MIT-licensed
perfect
Does anyone know how can I make a "rejoin" thing on velocity?
So the player gets kicked from current server and immediately gets reconnected
listen to the kick event, check the reason or server status and just set the redirect server as the current server

Okk
How does one do error handling for something like this:
ConnectionRequestBuilder connection = p.createConnectionRequest(server.getServer("event").get());
connection.connect();
.connect returns a future with a result
What’s the easiest way for me to have global variables between servers
Just a database? Or
https://jd.papermc.io/velocity/3.0.0/com/velocitypowered/api/proxy/ConnectionRequestBuilder.Result.html, you can then check Result#isSuccessful or .exceptionally
zestarr: yeah DB or messaging service or some combination thereof
Ok ty, and if I want to send a player to a server do I need to import velocity via maven into my spigot plugin?
Or how does that work? Never used velocity
Ok ty!
is there any good tutorials/resources to start developing plugins for velocity?
https://docs.papermc.io/velocity/cat/dev/getting-started is worth reading
thank you ❤️
😻
look at my source code i handle it
im quite noobie, can a velocity server run a bungee plugin and vice versa?
no
There is a plugin which triiiiiiiess that, but, unsupported, expect bugs, etc, etc
i think i might have seen a plug-in that can try it
yeah i can’t imagine it’d be bug free
good intel, thanks 😛
Hello! How can i cancell all player commands?
I try to use something like this, but it is not work for me
public void onPlayerExecuteCommand(CommandExecuteEvent e) {
if (PlayerData.INSTANCE.isAuthorized(player.getUsername())) return;
e.setResult(CommandExecuteEvent.CommandResult.denied());
}
did you add @Subscribe?
Yes
for debug, i add some lines of logs. I see logs in console. but command not canceled
probably an issue with velocity not cancelling the forwarding of those commands
i think i’ve experienced something of the sort before?
Sorry ahead of time I am new to futures. I am trying to monitor the result of sending a player to a server. When I look at the future when it completes is always say CONNECTION_IN_PROGRESS. I'd like to be able to see when it hits the SUCCESS state as well.
connection.thenAccept(result -> System.out.println("Result: " + result.getStatus().name()));```
This is always the result I never am able to see the flow finish.
```Result: CONNECTION_IN_PROGRESS```
I was wondering if it was possible to determine if a player was connecting via a forge client or via a vanilla client?
Player.getModInfo() is not present when joining via forge, player.getClientBrand() just returns null in either cases.
probably redis
strongly depends on the game version
1.12.2 and older use this system, but you’ll have to wait till the first server join is complete
1.13 and newer you’ll have to register and listen to the appropriate login plugin channels yourself
for the brand see https://jd.papermc.io/velocity/3.0.0/com/velocitypowered/api/event/player/PlayerClientBrandEvent.html
declaration: package: com.velocitypowered.api.event.player, class: PlayerClientBrandEvent
before that it’ll always be null
@fossil sundial Is there any eta for this issue https://github.com/PaperMC/Velocity/issues/774 ?
You’re barking up the wrong tree. I did what I had to before my exams end but other than that I’m not available till after July 25th
Either someone else does it or it’s gotta wait
Sorry
Sure good luck with your exams 🙂
Can I be sure that
LoginEvent is fully completed (whatever how long it takes)
until
ServerConnectedEvent is fired for a player? because that doesnt seem to be the case
Yes unless you have a plugin or you yourself are calling a connection request in this specific event
^
After C->S encryption response, and the ACK from the server, what packet is expected next from the server? I can't seem to find the doc
On the topic of connection failures I reported historically, we've narrowed it down to this malformed packet from the server to the client immediately after the encryption response is acknowledged https://i.cwlf.uk/wqQly
Either set compression (optional) or login success (according to https://wiki.vg/Protocol#Login)
Or do you mean the first packet on the play state?
Using Component.translatable, does it parse & as hex/formatting or whatnot?
Or is it only the funny gambit symbol
Any idea how I can make it do so
not
I've done it in the past, but with using .translatable
don’t use legacy
wdym by that
translatable are meant to be text only i think, you do the formatting yourself
^
all g
Is there any way for a backend server plugin to send a message to all velocity proxies?
I'm using Herochat which sends chat messages through the messaging channel but only for the proxy the message originated from and I was wondering if that way you could get cross-proxy messages 😅 Just a very wild idea that crossed my mind :D
You’d have to use something else like redis or rabbitmq as plugin messaging requires an active player connection to to work
As for 1.19 and newer this isn’t working cause the api for it is missing; see the 3.1.2 milestone on GitHub for that; it’s still indev
I mean... you wouldn't want to send a message to a proxy that has no players connected so, not necessarily what would be required in this case?
Aw, unfortunate but thanks for letting me know. Maybe I'll ask for reddis support though I doubt it'll come any time soon 😅
Ah I see, redis would be the easier choice then, I see that :D
Any advice on this error?
[15:54:06 ERROR]: Couldn't pass ServerPreConnectEvent to lendnet
java.util.NoSuchElementException: No value present
at java.util.Optional.get(Optional.java:143) ~[?:?]
at lendmark.net.listeners.ServerSwitch.ServerPreConnectEvent(ServerSwitch.java:39) ~[?:?]
at lendmark.net.listeners.Lmbda$40.execute(Unknown Source) ~[?:?]
at com.velocitypowered.proxy.event.UntargetedEventHandler$VoidHandler.lambda$buildHandler$0(UntargetedEventHandler.java:47) ~[velocity.jar:3.1.2-SNAPSHOT (git-662fbc4e-b159)]
at com.velocitypowered.proxy.event.VelocityEventManager.fire(VelocityEventManager.java:598) ~[velocity.jar:3.1.2-SNAPSHOT (git-662fbc4e-b159)]
at com.velocitypowered.proxy.event.VelocityEventManager.lambda$fire$5(VelocityEventManager.java:479) ~[velocity.jar:3.1.2-SNAPSHOT (git-662fbc4e-b159)]
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) [?:?]```
RegisteredServer server1 = server.getServer("lb01").get();
RegisteredServer server2 = server.getServer("lb02").get();
if (server1.getPlayersConnected().size() > server2.getPlayersConnected().size())
Utils.sendPlayerToServer(server2, player);
else if (server1.getPlayersConnected().size() < server2.getPlayersConnected().size())
Utils.sendPlayerToServer(server1, player);
else {
int min = 0;
int max = 1;
int random_int = (int) Math.floor(Math.random() * (max - min + 1) + min);
if (random_int == 1) {
Utils.sendPlayerToServer(server1, player);
} else {
Utils.sendPlayerToServer(server2, player);
}
}```
check ifpresent on any optional you use
I don't see anything optional there?
I mean it doesn't work without it
I think
it also clearly isn't working with it
read the javadoc
because it doesn’t work?
It works correctly
then it’s placebo
well then why are you asking for support if it's working fine
..because of the error
so it isn't working....
It is, but spams the logs
i give up
what do you get
The event gets fired before the player has a server
also, you aren’t checking if your optionals are present
That's what I'm saying
I added a check for if there even is a server present
might work now
I take that back
Still throws the error
if(player.getCurrentServer().isPresent()) {
if (player.getCurrentServer().get().getServerInfo().getName().equals("asdasdasd")) {
RegisteredServer server1 = server.getServer("lb01").get();
RegisteredServer server2 = server.getServer("lb02").get();
if (server1.getPlayersConnected().size() > server2.getPlayersConnected().size())
Utils.sendPlayerToServer(server2, player);
else if (server1.getPlayersConnected().size() < server2.getPlayersConnected().size())
Utils.sendPlayerToServer(server1, player);
}
}```
And yes lb01 and lb02 exist
send a paste link to your exception
and what line the line the exception occurs at is
what is line 38 of ServerSwitch.java:39
HOW AM I SO STUPID
if (player.getCurrentServer().get().getServerInfo().getName().equals("ob-main") && !event.getOriginalServer().getServerInfo().getName().equals("ob-main")) {
player.sendMessage(Component.text("§eUnloadujem pack.."));
player.sendResourcePack("https://lendmark.blob.core.windows.net/lendmark/default.zip");
}```
kill me, please
don’t worry, everyone makes mistakes
have fun developing on velocity!!
Thank you :D
You should use the resource-pack builder
You can get an instance from the proxyServer
Is that something new? Don't think I saw it when I did this a couple months ago. Either way, thanks!
I think it was introduced with 3.1
Has some neat options for the newer versions
declaration: package: com.velocitypowered.api.proxy, interface: ProxyServer
Yeah, that's probably why I haven't implemented it that way. Will do o7
The resource pack status event will fire back with the same resource pack info instance you built from the builder
So you can track it easily
Neat!
That was the whole idea behind this
I'm just glad I got this stupid bug fixed
It's been like that since december and I hate it
Technically you should still check isPresent() before .get()
The optionals are gonna be replaced with Nullable values on polymer
No reason to have the extra overhead
Yeah
Just coming from bungee where values can be randomly null without documentation we thought we’d be clearer
Also, one more question. I've been trying to move over our chat related stuff over to the proxy, but the formatting doesn't seem to work. Chat filter works fine.
For 1.19?
public class Chat {
ProxyServer server;
public Chat(ProxyServer server) {
this.server = server;
}
@Subscribe
public void ChatEvent(PlayerChatEvent event) {
Player p = event.getPlayer();
if(!p.getCurrentServer().get().getServerInfo().getName().contains("ob")) {
String color = "§7";
if (p.hasPermission("chatformat.whitecolor"))
color = "§f";
String prefix = "§f";
if(p.hasPermission("group.creeper"))
prefix = "§2§lCreeper";
if(p.hasPermission("group.wither"))
prefix = "§8§lWither";
if(p.hasPermission("group.dragon"))
prefix = "§d§lDragon";
if(p.hasPermission("group.youtube"))
prefix = "§f§lYou§c§lTube";
if(p.hasPermission("group.helper"))
prefix = "§9§lHelper";
if(p.hasPermission("group.moderator"))
prefix = "§b§lMod";
if(p.hasPermission("group.builder"))
prefix = "§a§lBuilder";
if(p.hasPermission("group.admin"))
prefix = "§c§lAdmin";
if(p.hasPermission("group.majitel"))
prefix = "§a§lMaji§2§ltel";
String format = prefix+color+p.getUsername() + "§8» " + color + event.getMessage();
event.setResult(PlayerChatEvent.ChatResult.message(format));
}
Pattern pattern = Pattern.compile(String.join("|", Main.badwords), Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(event.getMessage());
boolean found = matcher.find();
if (found) {
//p.sendMessage("§c§m-----------------------------------------------------");
//p.sendMessage("§cNadávanie a obchádzanie chatového filtru je proti pravidlám.");
//p.sendMessage("§cAk sa pokúsiš o obchádzanie filtru, budeš umlčaný!");
//p.sendMessage("§c§m-----------------------------------------------------");
p.sendMessage(Component.text("" +
"§c§m-----------------------------------------------------\n" +
"§cNadávanie a obchádzanie chatového filtru je proti pravidlám.\n" +
"§cAk sa pokúsiš o obchádzanie filtru, budeš umlčaný!\n" +
"§c§m-----------------------------------------------------").clickEvent(ClickEvent.openUrl("https://lendmark.sk/pravidla")));
//p.playSound(p.getLocation(), Sound.BLOCK_ANVIL_PLACE, 10, 1);
p.playSound(Sound.sound(Key.key("anvil_place"), Sound.Source.BLOCK, 1f, 1f));
event.setResult(PlayerChatEvent.ChatResult.denied());
}
}```
All version really
Wrote this before 1.19 anyway
Also the audio methods won’t work
Yeah, I saw 
We don’t implement those. They’re in there because adventure has them
Ah, okay
Guess I'll have to live without BLOCK_ANVIL_PLACE
Another thing, is there some Velocity alternative to this?
String color = "§7";
if (p.hasPermission("chatformat.color"))
e.setMessage(ChatColor.translateAlternateColorCodes('&', e.getMessage()));
if (p.hasPermission("chatformat.whitecolor"))
color = "§f";
String format = papi+color+"{PLAYER_NAME} §8» "+color+"{MESSAGE}";
format = format.replace("{PLAYER_NAME}", p.getName());
format = ChatColor.translateAlternateColorCodes('&', format);```
Sound requires tracking entities- we aren’t keen on doing that
From our Bukkit chat plugin
Adventure has a legacy chat serializer
Fine with me, just wanted to try it
is that a bad or a good thing
It would work for what you’re doing here
But you should really take a look at minimessage
It’s new in 3.1.2
Could MiniMessage achieve this?
(in the replace chat messages thing case)
The format is more intuitive than §something
For me as a developer sure, but players are used to & for some reason
It's a perk you can buy with a rank (since I prefer to not do p2w perks)
& / § are legacy but you can use LegacyComponentSerializer
Yea for that the legacy component serializer works
i thought 1.19 included MM auto parsing & and §?
is that a adventure thing?
maybe only in paper
yeah
I’m not sure, you’d have to ask the adventure guys
gotcha
this is probably not the right URL but it is the 3rd result on google 💀
It’s indeed not the right url https://jd.adventure.kyori.net
you would do LegacyComponentSerializer.legacyAmpersand().deserialize(string)
google spiderbots failing 
shows me outdated versions of adventure api instead
That’s the reason I didn’t link to a specific version but the index
ah xD
i mean thrus:
Yes
I'm a bit lost
if(p.hasPermission("chatformat.color"))
event.setResult(LegacyComponentSerializer.legacyAmpersand().deserialize(event.getMessage()));```
It's yelling at me that it wants a TextComponent, which if I do that it starts yelling at me that it wants a chat result
no, minimessage does not parse legacy
Wait I might have it
u would do ChatResult.message(component)
i assume
for the setResult
event.setResult(LegacyComponentSerializer.legacyAmpersand().deserialize(PlayerChatEvent.ChatResult.message(event.getMessage().toString())));
also demands a text component
well now it wants a string
god damn
no nono
do
event.setResult(ChatResult.message(legacycomponent...))
I just realised that may have been useless
This is what happens
String format = prefix+color+p.getUsername() + "§8» " + color + event.getMessage();
event.setResult(PlayerChatEvent.ChatResult.message(format));```
yes so now
if(p.hasPermission("chatformat.color"))
color = LegacyComponentSerializer.legacyAmpersand().deserialize("&").toString();
if (p.hasPermission("chatformat.whitecolor"))
color = "§f";
surround format with the legacycomponentserializer
Oh there
W
I get what you're saying now
ye
this is not how u use legacycomponentserializer brw
deserializing & only i mean
but i think u know how it works now
good luck sir
That's a string, it wants a text component
String format = prefix+color+p.getUsername() + "§8» " + color + event.getMessage();
if(p.hasPermission("chatformat.color")) {event.setResult(PlayerChatEvent.ChatResult.message(LegacyComponentSerializer.legacyAmpersand().serialize(format)));} else {event.setResult(PlayerChatEvent.ChatResult.message(format));}
oh
use i believe
PlainTextComponentSerializer
for the else
that will keep it plain with no colors or decorations iirc
Won't that reset the prefixes and shit?
hmmm
well you could do this
so get the legacycomponentserializer
serialize the prefix and formatting etc
then u can append another component
in which case u can append the message
so legacycomponentserializer, serialize prefix, formatting, etc,. then append plaintextcomponentserializer and serialize the message
if you’re hard coding the format why not just use components
I'm not exactly sure how to use components (as in replacing stuff ext.)
It's something new to me
iirc its
.replaceText(lambda -> lambda.matchliteral(..)) or something like that
its pretty straightforward
u can match regex or literal
wym
For example in that context with the chat formatting
sí
Because in a String all you need to really do is "asdasd" + p.getUsername() and it's there
not sure if that were to work with components
That's why I've tried avoiding them in the past
No, you can't, you would use append to combine multiple components together.
then ig just stick with this
if i remember correctly, replacing would like like
String format = "%prefix% %username%: %message%";
Component component = LegacyComponentSerializer.legacyAmpersand().deserialize(format).replaceText(config -> config.match("%prefix%").replacement(prefix))```
i don't remember tho
unsure if you have to do replaceText per each placeholder

you don't have to do it that way, there's always
String format = prefix + username;
Component formatComponent = LegacyComponentSerializer.legacyAmpersand().deserialize(format);
formatComponent = formatComponent.append(PlainTextComponentSerializer.plainText().deserialize(event.getMessage());
event.setResult(ChatResult.message(formatComponent));```
interesting
si
so this would (theoretically) replace the & in the things?
Using a ComponentSerializer, how can i serialize a translatable component (add color from hex etc)
the legacy will, the plain will not
plain = well, plain
legacy will format msgs with & or § depending if you use legacyAmpersand or legacySection
legacyAmpersand is &
so as you see on the 2nd line, we deserialize the formatting, which will format the prefix and username assuming they contain & and §
wait
for the 3rd line, we append a plain message (the message sent.. i think?)
wouldn't it be easier to just replace all & with § for String color?
no because either way it is legacy
so even with § you'd have to use legacycomponentserializer, but use legacySection
good luck
remember to check out adventure's javadocs and other documentation as well
How can I apply a serializer to a TranslatableComponent
haha maybe this will work
if(p.hasPermission("chatformat.color")) {
if(event.getMessage().contains("&")) {
format.replace("&", "§");
}
}```
will make it a component later
my brain stopped working about 10 minutes ago
yeah but there's no point of replacing either way
and also
if someone sends a message
i.e.
they're like hi i like this & that
then it will replace & with §
If thats what you're struggling wth
so it might be a good idea to make it a pattern you recon
Yeah, kinda
why are you trying to replace it though
there's no advantage to replacing it because it has to go through the legacycomponentserializer anyways
the serializer will handle all the formatting for you
if(p.hasPermission("chatformat.color")) {
if(event.getMessage().contains("&")) {
VelocityChat.color(message);
} else {
Component.text(message);
}
}
I'd use something like that
obviously thats not finished but you get the jist

private static final LegacyComponentSerializer serializer = LegacyComponentSerializer.builder().character('&').hexCharacter('#').hexColors().build();
public static TranslatableComponent translatable(String key) {
return (TranslatableComponent) serializer.deserialize(serializer.serialize(Component.translatable(key)));
}
this feels very wrong
what are you trying to do
Just apply hex colors and such to a translatable component
And return it as a TranslatableComponent
Can't even tes it
errors?
Having some super strange issue in help channel
nah just something in velocity bugging out for a few people
Either that or my environment
Yes
is it up to date?
is your velocity up to date?
It's not a plugin issue
its an internal issue
I've already talked with Five about it
its super weird
what is on your backend?
protocollib?
you tried without plugins
and all up to date server softwares?
paper is up to date and velocity?
Yeah latest everything
Weird thing is it just stopped working properly after a restart
and without your plugin does it work?
Yes I obv tested that
so your plugin is causing the issue except it is an internal issue
are you shading adventure by any chance?
into your plugin
Ive tested with no plugins
Yea
have you tried letting your config regenerate?
Looks like a very common rising issue
Few other people have had this today alone
rip
Me and a friend who was running a local env, as well as another user
All the same issue and no solution has been found, nor the cause of it
Regenerating the config does nothing
Same issue
its really strange
rip very weird
Also still have no clue about applying the RGB and whatnot to a translatable component
What are you even trying to accomplish here
I don’t know of a single part the velocity api has that doesn’t accept a generic component as parameter
Well I want to be able to return a TranslatableComponent, with RGB and whatnot applied
So?
Then I want to be able to modify arguments
oh wait yeah, matt, why do you serialize to legacy then deserialize from legacy
Would it be better to apply arguments before applying RGB
Can't cast that to a translatable component
There’s a translatable component builder
But otherwise Component.translatable(key).color(…)
keys must not contain anything but themselves
Otherwise they’re not translatable
like “multiplayer.disconnect.outdated_client”
That is a translatable key
Yeah I understand that
And that key must only be that key.
If you look at the json this translates to:
You’ll always have the formatting outside the translatable section
The result is the message that is processed. Not a component.
With a regular message you'd do something like this
public static Component format(String message) {
return serializer.deserialize(message);
}```
Would apply formatting and whatnot
public static TranslatableComponent translatable(String key) {
return Component.translatable(key); // apply formatting here
}```
Otherwise the message must be a json
So is it not possible to apply the formatting and still return that as a TranslatableComponent?
It is if you apply the formatting to an existing component …..
Components make up compounds
They’re json elements
You have to understand that calling .color(…) wraps the translatable component in another component
Which is why what you’re doing won’t ever work
Translatable components themselves cannot be styled but if you wrap components around them like with .color(…) then that will work
Can you send players interactive books from velocity using adventure?
or is that like not implemented
Would be useful for GDPR shit
Probably not, but if its possible the most you could do is just open.the ui, not actually give them a book in inventory
regardless its probably best with a plugin on back end server and maybe some syncing between them and proxy
Idk if there's any implementation on the proxy rn though
I want to open the UI
just your classic "You can steal my data" prompt
Sorry; also a feature that requires a lot more tracking
To use it the proxy would need to interact with the player inventory
That said
I may make a plugin someday in the future that will allow usage of these features
(Requires a plugin downstream to work obviously)
i mean, would be easy if it's a "on first join" thing
no need to worry about putting an item back, if that makes sense
all you'd do then is construct the packets and send them over
I've got a very weird bug on my hands
With my /lobby command thingy
For some reason, it only works on either the lobby servers or "ob-main"
I'm probably blind, but I don't see what could be wrong
if done on other servers nothing happens
package lendmark.net.commands;
import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.command.SimpleCommand;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ProxyServer;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import lendmark.net.Main;
import lendmark.net.utils.Utils;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.util.Optional;
import java.util.Random;
public class lobby implements SimpleCommand {
ProxyServer server;
public lobby(ProxyServer server) {
this.server = server;
}
@Override
public void execute(Invocation invocation) {
CommandSource commandSource = invocation.source();
Player player = (Player)commandSource;
RegisteredServer server1 = server.getServer("lb01").get();
RegisteredServer server2 = server.getServer("lb02").get();
if (server1.getPlayersConnected().size() > server2.getPlayersConnected().size())
Utils.sendPlayerToServer(server2, player);
else if (server1.getPlayersConnected().size() < server2.getPlayersConnected().size())
Utils.sendPlayerToServer(server1, player);
}
}```
the only other things that could be interfering with it are the ServerPreConnectEvent and the ServerPreConnectEvent
ServerPreConnectEvent
@Subscribe
public void ServerPreConnectEvent(ServerPreConnectEvent event) {
Player player = event.getPlayer();
if(player.getCurrentServer().isPresent()) {
if (player.getCurrentServer().get().getServerInfo().getName().equals("ob-main") && !event.getOriginalServer().getServerInfo().getName().equals("ob-main")) {
player.sendMessage(Component.text("§eUnloadujem pack.."));
player.sendResourcePack("https://lendmark.blob.core.windows.net/lendmark/default.zip");
}
if (player.getCurrentServer().get().getServerInfo().getName().equals("auth")) {
RegisteredServer server1 = server.getServer("lb01").get();
RegisteredServer server2 = server.getServer("lb02").get();
if (server1.getPlayersConnected().size() > server2.getPlayersConnected().size())
Utils.sendPlayerToServer(server2, player);
else if (server1.getPlayersConnected().size() < server2.getPlayersConnected().size())
Utils.sendPlayerToServer(server1, player);
}
}
}
ServerPostConnectEvent
@Subscribe
public void ServerPostConnectEvent(ServerPostConnectEvent event) {
Player player = event.getPlayer();
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeUTF("PlayerVersionChannel");
out.writeUTF(player.getCurrentServer().get().getServerInfo().getName());
out.writeInt(Via.getAPI().getPlayerVersion(player));
out.writeInt(server.getPlayerCount());
player.getCurrentServer().get().sendPluginMessage( MinecraftChannelIdentifier.from("lm:playerversionchannel"), out.toByteArray());
}
}
Don’t send a resource pack in pre connect. The client will always decline a resource pack while it can’t display the prompt
That's fine, players coming from the Oneblock server have already accepted a pack as it's forced there. It only serves to reset it after they go for example on a different mini-game
So they don't have the different UI elements ext. for no reason
You’re rebalancing twice
Line?
You call sendplayertoserver in the pre connect too
Why
You already have a connection in flight
..is there a better way to do that?
The event won’t be called if the player is not under way to be connected to a new server
Why are you trying to shoot yourself in the foot
That's intended behavior
Auth has the GDPR shit ext.
That’s unsupported btw
Would be kinda useless if the player got sent to another server which has logs before giving consent
every time I see auth I have to figure it’s a standin for a piracy plugin
You don't understand. The only thing a player does there is say "I agree to asda ext. ext."
If they have consent all the server does it send them on their way
That’s fine then
I’m not sure I follow your flow then
But don’t send a player elsewhere while you have a connection in flight
You’ll create a loop
Cause sending a connection to flight causes another connection to be in flight
See the issue?
Yeah
I'll probably add something to cancel the old connection
But that still doesn't solve the issue why only the servers in the event do something with the hub command
Now you lost me
My issue is that when I do the /lobby command as seen above on lb01, lb02 or ob-main, it works
But if I do it on one of the other servers it doesn't do anything
Just seems to get canned
It's likely something incredibly dumb, but I'm blind
Something seems to be cancelling it, but I don't see the cause
See the issue?
anybody else
sad
@bold wharf I apologise for the ping but i think that yesterday you (or Five) mentioned about Velocity's debug mode? How can i enable that
I don't think that there is one bar specific packets
I may of said that I really needed to add one at some point
but, not aware of an existing one.
Im still having an issue where i cant ping nor connect to my local server
(outside of the various system flag specific ones)
Me and a friend both encountered this yesterday seemingly after a restart
No clue what could be causing it at all
Doesn't show in console when i attempt to ping the server and instantly shows the Disconnected screen when i attempt to connect
I mean, that gives very little for us to go off
Well that's virtually all I have to go off myslef
I am struggling to even try debugging this
I mean, if you can do code stuff, ServerChannelInitializer
add a thing there to see if the channel bootstraps
but, I mean, adding logging for an issue we have 0 basis of is pretty "no go"
Shit like that is generally "incrementally flood the software with logger statements until you nail down where shit is going"
"Disconnected" is literally just the generic "we where told to fuck off"
does velocity support sending sounds to an audience?
no, sounds require a location and velocity doesn’t track that
alright thanks
(that's also not really why, it would need a registry which velocity would have to maintain for like all supported versions)
i mean, you could just rely on the dev to enter a key?
and a location?
or am i missing something
Hello, is there a way to get the players locale even before they connect to any server? or are in a world loading screen?
hi, im trying to initialize a discord bot using JDA in the proxy initialize event, but i keep getting this error. can somebody help me out? im not too experienced with java
heres the code
JDA likely isn't being shaded, you need to setup shading in your build.gradle/pom.xml
i see, are there any resources where i can learn more about that?
i dont know much about java
the JDA wiki has a page for setting it up with gradle at https://github.com/DV8FromTheWorld/JDA/wiki/2)-IntelliJ-IDEA-Setup, for maven see https://maven.apache.org/plugins/maven-shade-plugin/usage.html
thank you, ill check it out
It's after login success, appears to be in the Forge handshake immediately after START is handled on both sides, the client is disconnected with SPacketDisconnect
Forge claims it receives an unregistered packet, Velocity disconnects the user.
Velocity:
[connected player] Player (/103.121.18.77:1142) has connected
[debug] Encoding packet SetCompression with id 3
[debug] Encoding packet ServerLoginSuccess with id 2
[debug] Encoding packet Handshake with id 0
[debug] Encoding packet ServerLogin with id 0
[server connection] Player -> forge has connected
[server connection] Player -> forge has disconnected
[connected player] Player (/<snip>:1142): unable to connect to server forge
com.velocitypowered.proxy.util.except.QuietRuntimeException: The connection to the remote server was unexpectedly closed.
This is usually because the remote server does not have BungeeCord IP forwarding correctly enabled.
See https://velocitypowered.com/wiki/users/forwarding/ for instructions on how to configure player info forwarding correctly.
[debug] Encoding packet Disconnect with id 26
Forge:
[Server thread/TRACE] [FML]: Handshake channel activating
[Server thread/DEBUG] [FML]: FMLHandshakeServerState: null->FMLHandshakeServerState$1:START
[Server thread/DEBUG] [FML]: Next: HELLO
[Server thread/INFO] [net.minecraft.network.NetHandlerPlayServer]: S_Doppler lost connection: Internal Exception: io.netty.handler.codec.EncoderException: java.io.IOException: Can't serialize unregistered packet
Client:
[Netty Client IO #18/TRACE] [FML]: Handshake channel activating
[Netty Client IO #18/DEBUG] [FML]: FMLHandshakeClientState: null->FMLHandshakeClientState$1:START
[Netty Client IO #18/DEBUG] [FML]: Next: HELLO
[Netty Client IO #18/INFO] [FML]: Unexpected packet during modded negotiation - assuming vanilla or keepalives : net.minecraft.network.play.server.SPacketDisconnect
I've since rebuilt forge with some extra debug logging, it looks like the START state completes on both ends, but the HELLO state never begins; my conclusion up to this point is Velocity is mishandling a retransmitted packet.
Why it only occurs only for new players on ~14% of first time connections https://i.cwlf.uk/dJNag, I have no clue, presumably something to do with overrideDim; but it doesn't occur if we remove Velocity from the stack.
not working
it does work
I can't view title
Component mainTitle = Component.text(traductColour("&5Sei sotto controllo anti-cheat!")); Component subtitle = Component.text(traductColour("&7Leggi la chat e non uscire!")); final Title title = Title.title(mainTitle, subtitle); target.showTitle(title);
Forge 1.13 and newer isn’t supported; what are you’re trying to do here?
Where are you sending that from? The client will ignore it if it can’t display it
since it looks like you're mixing legacy and components, make sure to try it on a vanilla client, lunar is known to break stuff with components
(or just don't mix them)
do any of you guys know of a working** Global TAB player list for Velocity**? many weeks researching and testing velocity plugins for it without luck and mixed results, it just doesn't work, some kind of work, but when players leave or switch servers, the TAB doesnt update, I know TAB by Netz was perfect but, with all the drama is not supported for Velocity anymore, works but only on back end servers and NO global tab list 😦
i’ve seen plenty of global ones work myself
example?
old as hell
parts of the code may be relevant to replicate it to modern standards if necessary
yeah then build it yourself smh
I saw that one before, gonna give it a quick try, but I am pretty sure it will be the same result as the others, that are that old, when players switch servers ,the playerlist does not update
Then add that yourself
i don’t think it’d be that hard really
maybe the sorting would be but like i said it’s done all the time
from 3 years ago, what do you think java 11? -_-
Maybe it’s just best to make your own with similar logic and whatnot to the one i linked
@fossil sundial a semi stable version of my plugin just got released so jus so you know https://github.com/adde0109/Ambassador
The limit is the Velocity's api. I can't do proper ping forwarding that FML2 understands with the api limitations
One thing I would like for the sake of showing FML2 medlist at ping is to allow plugins customize the Server ping more
I also got bstat working and my plugin is already running on a network
Right now I want as many people as possible to test and report to me if they find any issues or want to request a feature. I'm open.
After my exam period I’m open to suggestions with the api for server pings
But not before
Ok. Understanding
I just found out that the recent pixelmon mod ships with intergrated forge client reset packet mod
So I will try to integrate with that so people that has the mod can use it.
To be clear it's optional to have the client side mod
But if the mod is already there, why wouldn't it use it
Hi, after velocity update to latest version for support 1.19, I have issue with messages he is showing in the actionbar not in the chat.
update viaversion to the latest dev build
Thank you ❤️
from velocity
for target
I've been trying to create a Velocity plugin for about 2 days but only get the error The plugin file Nerf in Minecraft Proxy.jar appears to be a Bukkit or BungeeCord plugin.. Here is the code. I usually build with Intelij Artifact. Hope someone can help me
Main.java
package net.nim.proxy;
import com.google.inject.Inject;
import com.velocitypowered.api.command.CommandManager;
import com.velocitypowered.api.command.CommandMeta;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
import com.velocitypowered.api.plugin.Plugin;
import com.velocitypowered.api.proxy.ProxyServer;
import net.nim.proxy.commands.TestCommand;
import java.util.logging.Logger;
@Plugin(id = "NIM-Proxy", name = "Nerf in Minecraft Proxy", version = "1.0", description = "Proxy Plugin", authors = {"Jonah Schmidt"})
public class Main {
final ProxyServer proxyServer;
final Logger logger;
@Inject
public Main(ProxyServer proxyServer, Logger logger) {
this.proxyServer = proxyServer;
this.logger = logger;
logger.info("Nerf in Minecraft Proxy Plugin Loaded!");
}
@Subscribe
public void onProxyInitialization(ProxyInitializeEvent event) {
CommandManager commandManager = proxyServer.getCommandManager();
CommandMeta commandMeta = commandManager.metaBuilder("test").build();
commandManager.register(commandMeta, new TestCommand());
}
}
TestCommand.java
package net.nim.proxy.commands;
import com.velocitypowered.api.command.SimpleCommand;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
public class TestCommand implements SimpleCommand {
@Override
public void execute(Invocation invocation) {
invocation.source().sendMessage(Component.text("Test!").color(NamedTextColor.AQUA));
}
}
do you have any resources?
like a plugin.yml or smth
no
weird
oh wait
this ?
I deleted the file now I get the error Did not find a valid velocity-plugin.json
plugin.yml shouldn't really effect anything
and ive never seen a velocity-plugin.json in a velocity plugin
Before I deleted the plugin.yml I got the error The plugin file Nerf in Minecraft Proxy.jar appears to be a Bukkit or BungeeCord plugin. The error is now
Use a proper build tool like gradle or maven
what's your build tool 0,o ant script?
they mentioned they're using the intellij artifact thing
hm, well you need to run the velocity annotations processor
yes
what ?
I don't use Maven or Gradle. Tried it at the beginning but couldn't manage to create a project with it
well unless you think you're up for writing your own annotation processor i think now is a good time to learn
okay
If you download the minecraft development intellij plugin it'll setup the project for you when creating it
Yes
Okay, I have now set up a Velocity project and when I try to build it I get the error error: Invalid ID for plugin net.nim.proxy.Main. IDs must start alphabetically, have alphanumeric characters, and can contain dashes or underscores.
am... I don't understand
I think it expects a lowercase name
I have to lowercase this?
@fossil sundial
Hi, I want to make a pull request with a slight change inside ConnectionHandshakeEvent and I have two options.
- Pass the whole Handshake instance inside the event
- Pass unmodified Handshake#getServerAddress()
Which option do you prefer? or maybe there is a reason why this data is not passed to the event? or i should just make a fork for myself?
I’m not up for debate till my exams are over on the 25th
Ping me again then
where & who do i give money
me
oh my god it's corey my second favourite person
I have an idea for a way to do it
I just have this whole like, thing where it feels like somebody ripped a layer of skin off my brain
I also kinda don't like it either
(but, idk a better way to do it)
Do keep the queue in mind that we will need. That’s all I’m saying
thoughts was on incoming, place in a queue
fire event
once event has fired, basically while (queue.peek.isComplete, senderion)
Yes but the queue is also there to allow the proxy to fit messages in there it will send on its own
Remember commands are only partially signable
only partially
?
singable
❤️
(quickly edits the post)
Only the commands registered as chatlike through the chat registry
So do that first
We will need it to do this properly
Chat registry > Time disposition > Queue > Queue insertion
well we just have to use (essentially) what log4j uses to retain "order" internally, potentially some priority queue
No priority. Signatures are absolute
doing the queue is trivial in a sense, insertion is a pita
but, you just need to order based on time
how have you not have 5 million users complain about this issue on minehut @oblique haven
we've had a few
big caveat is popping said queue without just going back and making it blocking
not too many users on proxy->proxy where the issue sits (for us)
This is a queue with side-channel
You need to be able to insert something sideways with believable time spacing
Or else the server will raise a stink about too quick messages
Which is why velocity also needs an incoming delimiter
This will be a magic waitForApproprtiateInsertion() loop internally

why are we not insertion sorting here
Issue with insertion sorting is, well, racy
This will end up in a magic queue internally either way
any solution is going to have some kind of issue with high-latency systems
Which is why I said store time disposition
I don't see a very easy way around that
Time disposition also takes ping into account
only foolproof solution is to just remove the proxies interaction with this stuff
to calculate some magic delta which flushes the queue?
No
You work out the time difference between you and the client
so that when you go to add a thing to run, you don't end up fucking over the client
that'd be the delta, yeah
A stupid offset rule
what is bungeecord doing

ignoring it prolly
Removing it
yea, but nothing to do with flushing, it just's delta'd

Well
bungee removed support for sending that stuff to the server
they also just run pretty much everything on the network threads
if we're not buffering calls then we're going to have nasty race conditions
Bungee throws an IllegalArgumentException() if you call any send message or command function on the proxy with 1.19+
So they don’t care
clients care about ordered messages from other clients right?
Yes but that’s an issue the server has to deal with
so we're assuming the packets coming from the server are ordered?
then this makes the whole thing a bit more sensible
We don’t process server sent packets remember?
right
but we have to queue them in a way which makes sense to the client
if the proxy sends a message it has to mark it in the queue so we have to handle it at some capacity, which I assume is what the issue is for
We don't care about what comes from the server
we care about what we're passing to the server
so the server is the one caring about ordered-chat, not the client?
interesting, okei
Velocity doesn’t support sending signed messages as chat to the client for now
That’s another project entirely
multi-proxy environments will suffer from this I think
There’s an issue for it
right
Let’s leave the church in town for now and focus on the order issue
Whatever you come up with here
I probably won’t like it
But in all fairness I can’t think of a good solution myself
random bullshit go
ez
move chat back to the network thread
runs
This is part of why I think a custom messaging channel for modern proxies might be an idea
well if chat order is really broken with the client, we should handle it accordingly, this doesn't seem all that intense
maybe something cleaner than bungees messaging channel if people have ideas of that mess
yeah, would probably be nice for communication
But, then we could add things like a command/chat channel and just pass the unsigned crap through and let the server determine what it wants to do with it
Not that that doesn't create issues of it's own, but, y'know
I don't think ordered chat -> server is going to be necessarily difficult, especially if we're trying to fulfill the player's personal chat queue
I would be very happy if we could just add this to the velocity forwarding protocol: Ignore timestamp if timestamp is -6969 for example
But alas
That’s not a good option
I might take a crack at an implementation later tonight, I have a few ideas
I mean, I was just debating on that while using the pisser
It's far from ideal
But, I mean
it would solve so many other fucking issues
that would deal with the disposition mess at least afaik
then for chat, as I say, append future or whatever to a queue, fire event (which completes future on post), and after that, just have a task which drains the queue
only way I can see doing that without having some perma thread tryna deal with the queue
I don't think I'm understanding "out of order" chat, is there some writeup done on it? I know there was a write up done on signed messages specifically
messages have a timestamp on them
out of order means that it got a packet where the timestamp was earlier than the last packet we got
There is some caveats here that a badly timed clock sync, especially on modern hardware, can get them real good, but, we also pass stuff off into other threads for processing events, etc, which ofc makes a fair risk on our side
so the player -> proxy -> server channel is the only thing being checked against so somehow proxy -> server is becoming out-of-sync because the proxy is sending some packet like a command packet which makes the server believe the chat was out of sync?
is that what we're working with here
yes
okie doke
what am guessing here is that due to the magic of events firing, and maybe plugins, something somewhere is going sideways
@Subscribe
public void onChat(ChatEvent event) {
// send command
// result "accept"
}
``` crude but potential reproduction of the bug yes?
hm interesting, okei
that's one way to do it, yes
having a hardcoded "ignore me" thing is a good idea, tbqh
Like, we're not able to send signed packets over to the server anyways
Only if in forwarding mode
only if velocity-support is enabled yeh
I also wanna add some leeway to that mess
managed "order" of velocity should happen when client talks to velocity, so paper should abandon the desire to validate unsigned messages in this circumstance
unless there's some reason we want unsigned stuff to be ordered - if we force signed objects to be ordered and drop unsigned objects as "unordered" or "ignored" we can just skip this whole issue because we can guarantee on the velocity side that it won't be passing down "unsigned" values unless it's explicitly allowed, and unsigned commands should be blocked at the proxy level as well if such a case exists where we don't want to be passing it, along with unsigned "chat" at the server level
intents may change this but if you drop the command intent then the validation should be passed to the server which should probably be denoted in the forwarding, but I think that's the "sane" way to handle this without adding magic values everywhere
how do you "force" signed objects to be ordered is the issue
if you're not rewriting them then they should be known by the server at execution time - events are "completable" so we can track completion stages of a specific event and run the queue in order
future.whenComplete(() => <hook>) then it runs down to the next future and runs the same, adding hooks to futures even in post-completion works as expected as far as I understand
message 1 is sent
if there's no future handler it will just hold the value and stall (or should)
message 2 is sent
event handler for message 2 fin
event handler for message 1 fin
wat do?
future.whenComplete(() => <hook>) then it runs down to the next future and runs the same, adding hooks to futures even in post-completion works as expected as far as I understand
BasicQueue<CompletableFuture<SomeOrderedEvent>> queue;
while(true)
next = pop queue; // concurrent "await" here for the next event in line
next.whenComplete() // fire downstream packet
``` messages `client -> proxy` should exist in-order so when filling the queue we can "guarantee" this
when a Future lacks a handler it should just stall and calling whenComplete on a completed Future will just fire immediately
I mean, my theory was to basically generate the future into the queue
and then use the whenComplete to pop said queue
I liked your idea, yeah, it's sensible
I don't get where the while(true) comes into your thing
just jotted down
implementation wouldn't work exactly like that
whenComplete would need to call back to the queue to "free"
we can just use synchronized object locks for that though
basically, my thinking was that we didn't need to care in many respects
while true:
cache.wait();
next = cache.pop();
next.whenComplete(() => cache.notify())
``` something like this makes some sense
in example of event 2 finishing before 1, the whenComplete would run, peek, and see that the first one isn't completed, and just disappear
there's some cache locking methods needed to sync it up but meh
no, event 2 would finish and stall in the future, the future wouldn't be tied to any handler until it's popped by the queue
No need for it to stall
it wouldn't logically stall the cpu - it just would be resolved and be waiting to be popped
completable futures aren't lazy (at least from what I understand)
I'm lost on what you're thinking then
okay hold on
// FutureCallable = CompletableFuture<SomeChatHandleOrWhatnot>
private final Stack<FutureCallable> futures = new Stack<>();
public synchronized void emitChat(FutureCallable callable) {
futures.push(callable);
}
public void popChatQueue() {
var nextFuture = futures.poll();
nextFuture.whenComplete(item -> {
playerChannel.emitChat(item.someChatValueOrWhatnot());
popChatQueue();
});
}
basic writeup of my thoughts, which I think is what you were thinking
this Stack is FIFO
not FILO (even though I think java's impl is)
this would require a "dedicated thread" but could be pushed into an executor queue which wouldn't be super bad, then we can just "re-queue" the poll task in the executor if we want
then we can do a stack.pop().isComplete() check to see if we can dump more from the queue
Yea, I didn't want a deadicated thread was my thing
I mean, dedicated thread works but my concern was is that we'd ideally want a per-connection queue, not per player
we can run this through executors and make the task re-assign itself so it self-propagates over as many threads as necessary
we don't need to do this in a single thread layout
and thus having a thread manage that just made it seem annoying, and having thread pools for just popping a queue gets tedious and inefficent
having a dedicated thread brings more issues at scale
having some pool run through the client queues seems more sensible at scale since it can scale easier
and it's not like the executor will always have a "wait", we can pop an entire queue, channel the entire queue, and not re-prop if the queue is empty
and if there's minimal chat mangling this should work very in-line, executors polling the queue doesn't seem like a bad thing here
I don't see a much better way to even put this together other than synchronizing the output into some "pre-channel" buffer
my thoughts was,
fun onChat(Chat) {
val chatFut = ComputFut.doStuff(fireEvent, etc, etc)
stack.push(chatFut)
chatFut.whenComplete( stack.peek().isComplete ( pop until queue empty or !isComplete))
I mean, thats messy, and, kinda bleh, but, I mean, I don't really see a none bleh solution here
lets us use the existing threads already in play to just do the trivial work of popping the queue
why don't we use a "chain"
Future somePlayerCachedChatFuture = CompletableFuture.completed();
onChat(Chat) {
somePlayerCachedChatFuture = somePlayerCachedChatFeature.thenCompose(() -> /* new completable future */.whenComplete(/* flush packet */))
}
this would work no?
or rather wrapping the whenComplete on the outer layer
well, yes, but I wasn't aware on the thread safety inclinations of that
we can just lock the future
if it's all coming through the netty threads it should all be in-line
Well, the issue is the plugins
but, idk how we'd deal with that sanely anyways unless we just do the magic timestamp thing anyways
plugins can't sign so if we assume unsigned messages or commands are ignored for timestamps then this solves itself
which puts the "validation required" at the proxy level which is fine since we already der commands and messages
so if we Object.lock() the future then Object.wait() and Object.notify() make this super trivial for synchronizing future modifications
we'd probably use class level sync locks, or just some new Object() in a queue wrapper or something
lemme write up a quick POC
I mean, I see the concept, I didn't exactly wanna enforce 1 event at a time per player, etc
right no - me neither, I'm almost done writing it up I think
this is what I was thinking ^
https://paste.gg/p/anonymous/fa9a44c911fe4f2b836c6a875d1d4c49 basic output - I think I'm missing one, there's 149 printouts when there should be 150, I'll go figure out why that is - but this is the basic "idea"
that emit method looks sus
but, my brain is out of juice
like, submitting already completed futures to there already looks like a moot test case
I can add in latency imitating based executors to give a better idea, I’ll do 1-10ms latency per call for “handling”
Still need to figure out why 1 call is being omitted lol
https://paste.gg/p/anonymous/7935ead0e28b43938579865d7cac0bac here's a working prototype with "faked" latency between messages to a point where some are going to "cross-align"
unsure how this comes in to play with netty channels - but it seems to suggest that so long as the client is in-order it should process them sequentially
this is a rough mock up though - but it doesn't require a "dedicated thread" and allows for simple completable futures to chain off one another with a base "empty"
private CompletableFuture<T> uniWhenCompleteStage(Executor e, BiConsumer<? super T, ? super Throwable> f) {
if (f == null) {
throw new NullPointerException();
} else {
CompletableFuture<T> d = this.newIncompleteFuture();
Object r;
if ((r = this.result) == null) {
this.unipush(new UniWhenComplete(e, d, this, f));
} else if (e == null) {
d.uniWhenComplete(r, f, (UniWhenComplete)null);
} else {
try {
e.execute(new UniWhenComplete((Executor)null, d, this, f));
} catch (Throwable var6) {
d.result = encodeThrowable(var6);
}
}
return d;
}
}``` this kind of lets us play with it like that because it waits for the stage to be complete
and hinging synchronization on an object lock makes the most sense in java since iirc object likes are FIFO so acquiring the lock will put you in a read queue for the object which frees up after the sync block in emit
public void emit(CompletableFuture<Chat> chatFutureLocal) {
System.out.println("AI incr: " + MESSAGE_COUNT.incrementAndGet());
synchronized (lock) {
this.chatFuture.thenRun(() -> // after the current call finishes, whether it be now or later
chatFutureLocal.whenComplete(BasicChatQueue::emitChatDemo)); // setup a hook for this call (which could be now or later) to emit chat when complete
this.chatFuture = chatFutureLocal; // set the `chat future` to the local one to create the "chain"
}
}``` it's all very simple imo, but it should do the job for timestamp consistency unless the player is sending out-of-order packets which is _always_ an issue according to paper
I don't see how this breaks - we just can't push in our own proxy-owned information, so if we find a way to get paper to drop certain packets or "not care" about order for certain packets we can easily achieve the expected outcome through this ^ and all it does is back its way into the netty threads which initially controlled them
I don't exactly know how this will jump threads - but it should event 1 thread 1 emit message 1 <handle message 1 whenComplete in thread 1, thenRun in thread 2> event 2 thread 2 emit message 2 <handle message 2 whenComplete in thread 2, thenRun in thread n...>
this should be fine since the latest will dequeue on complete so we should have to worry about "artifact" values other than potentially the size of a chat packet which exists to push the chain along
and each player gets their own Queue since it uses a local lock object
(we can't use the chained future because it changes)
I mean, I can only see so much without it being in the actual impl which looks ass anyways
I mean the concept works in testing
I feel somewhat iffy on this, ngl; but, as said, there is no solution here which is gonna look great
The code in the proxy doesn't exactly look well designed for shoving this into is what I mean
I also don't know how/where you plan to hook it in and what the side effects of that will be
we put it in the BackendChannelPlay handler
then run it on handleChat and wrap the chat event in the future
then pass the future into the linked event inside of the backend play handler
we don't copy this 1-1 into velocity for sure - but the idea works which is what I'm grabbing at
my one thing is is that it looks like you can't have 2 events processing for a single player and that it's basically just gonna act like a glorified queue
if the 2 events are processing in 2 different threads you definitely can
I mean from a singular player
that's what I'm saying as well
public static CompletableFuture<Chat> chatFuture(String message) {
final Chat chat = new Chat(message, new Date());
TO_CALL.add(chat);
return CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(ThreadLocalRandom.current().nextLong(100, 200));
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return chat;
}, executor);
}
public static void main(String[] args) {
BasicChatQueue queue = new BasicChatQueue();
for (int i = 0; i < THREADS; i++) {
final int e = i;
var t = new Thread(() -> {
try {
for (int t1 = 0; t1 < 3; t1++) {
Thread.sleep(ThreadLocalRandom.current().nextLong(5, 10));
queue.emit(chatFuture("Test Thread %d (%d)".formatted(e, t1)));
}
} catch (InterruptedException exx) {
throw new RuntimeException(exx);
}
var x = THREAD_COUNT.decrementAndGet();
System.out.printf("Teardown for thread %d%n", x);
if (x == 0) {
BasicChatQueue.executor.shutdown();
}
});
t.start();
}
}``` these test markings `5-10ms between calls` and `100-200ms` of latency within __every__ chat call finishes in about 1 second
if these weren't running in parallel it would take like 2 minutes or smth
the Thread.sleep(100 -> 200) imitates handling of the packet, and the 5-10 in the bottom accounts over some form of latency
yea, I mean, idk, am tired and can't really judge it on all I can see atm
no sweat, this does seem like it's working though with fairly minimal lift
the idea is essentially
cachedFuture = completed future of some sort;
emit(newFuture) { (synchronized call)
cachedFuture (when finished) -> add chat handler to newFuture to emit packet
cachedFuture = newFuture
}
``` saying anything more is vastly over-complicating the scenario
then we drop the cached future and it's left to die in the GC
these futures are immediately dropped once the next handler runs through so we're always cleaning up behind ourselves
that's enough text dumping for me for now though - let me know what you think in the morning 🙂
keep in mind this impl doesn't work unless we let the backend server get rid of certain packets which have magic timestamps or something similar since our packets cannot go through this queue, keeps in mind latency and everything like that since TCP is transactionally based and will (usually? if not always) come in the order it's sent from the client
also, do note that you need to handle command packets in there too
that's fine, the CompletableFuture it takes would be generalized enough to contain whatever
java doesn't make that part hard so we have an easy win there
we can just do like Either<X, Z> either.caseOfX(x -> {}) or whatever we want to do, there's so many options in modern java
or whatever we want to do
I'm aware of the modern java constructs
we're java 11
😉
ugghh... I forgot about that
hopefully 18 soon 
jumping to latest LTS on next major is defo an idea
Considering MC requires 17 and most (all?) users running a proxy run a server, what's holding the update to java 17?
I dont wanna be chasing releases, however
major release, bumping java version mid cycle is bleh
Theres much to do for mc 1.19, but, post 1.19, I wanna do a release
we should probably follow MC client version spec for Velocity
eghh, Java is "technically" backwards compatible (for >9)
java 11 -> java 17 is rough
how so?
I mean, breaking everybodies environment mid cycle to tell them to update java is not nice
(well)
makes sense
sure, you're right, we shouldn't update until 1.19 is polished
as said, java bump would be ideally on a major, maaaybe on a minor
not my decision entirely, but, yea
I think the idea is to only push java on major MC version releases so that people don’t lose support for a version in the middle of a version @craggy pecan
I mean, we're not tied to mojang versioning
"official" policy for paper is the previous LTS iirc
Yeah but Velocity has built in stuff which handles backporting
I think that brings it to a different area even though paper itself doesn’t support legacy
Like I mean Via is just a hack - Velocity has built-in support (which is good) but Velocity usually does major revisions at the end of a version, or during the transition into a new version which seems like the most sane time to do such updates
Java 17 is LTS
I've seen that Velocity supports Brigadier, but I have not seen any signs of Minecraft related argument types being implemented. Are the Minecraft related argument types implemented by Velocity? For example, how do I make a command with an int range? (like 3..49, where 3 ≤ x ≤ 49) I understand that most of these will not make sense without more context on the server (like selectors), but registering these types of commands would make tab-completion much, much easier
See https://docs.papermc.io/velocity/dev/command-api#brigadiercommand, for an integer argument type you'd just use IntegerArgumentType.integer(3, 49)
yes i have seen that but those are just the core ones
i asked about the Minecraft specific argument types
Velocity only has access to the default Brigadier argument types, although there is probably a way to get the Minecraft argument types or inject custom ones (e.g. https://github.com/PaperMC/Velocity/blob/dev/3.0.0/proxy/src/main/java/com/velocitypowered/proxy/command/brigadier/StringArrayArgumentType.java ), but I don't think it is supported or recommended
I don’t see a reason to provide the game types to api
You wouldn’t be able to use them correctly without the data from the server or client anyway
Plus they’re highly version dependent and iffy in conformity
Was about to ask something similar, would there be any way to use a TextArgumentType? Obviously it uses a Text and not a Component, but is there any way it could be wrapped to provide the same output for the client as they type?
I’m not following
the tellraw command uses a TextArgumentType to parse a Component (well a Text in Mojang terms), and on the clientside it parses it to tell if it's valid as well (at least that's my understanding, unless I'm wrong and that has happened before)
Obviously I could re-implement this with GsonComponentSerializer, but then the client wouldn't have the same feedback
Doesn’t that exist already? No clue
Not from what I can tell?
Minecraft provides it as the parser minecraft:component, at least that's what I'm gathering from wiki.vg
Not sure how ArgumentType<T> provides what kind of type it parses? only ever looking into brigader and it's MC impl now
again, thats what i was asking for
while i agree about some of them being very context dependent, i don't exactly see the reason why some could be implemented
not sure about them being version dependent, as these don't necessarily change
No; you don’t understand; a lot of these use data that the client already has or the server has. To get that data the proxy would have to listen to every single packet for that context and build it. We ain’t doing that.
Again, i'm not talking about those
for example, the raw text component has no ingame context whatsoever
Five how can i send packets to a player without relying on a 3rd party api like protocolize?
Doesn't look like the Player interface allows you to send packets to a connection
Isn’t intended. Go look at how ViaVersion injects
The arguments velocity provides are the primitive arguments https://github.com/Mojang/brigadier/tree/master/src/main/java/com/mojang/brigadier/arguments
yes i saw those
That was meant as a reply^
thats why i was asking mainly
yeah no worries
Another question: if i use a BrigadierCommand for registering commands, will they work in some sort of legacy mode with older clients? (for example with ViaVersion)
Yes
I’m not open for discussion on any of this till the 25th
I have exams starting tomorrow
sure
cheers will do
i'll just implement an argument type and serializer for minecraft:component as Component and put the PR up
cause I feel as at least that one should exist for clients that support it
It is empty though
correct ^^
The impl would also be a placeholder
Cause the worst you could do is verify it
Otherwise the processing is client side
Brigadier tells the client “component here”
And nothing else
What you want is to have the proxy do a placeholder swap
Which is not an argument decoder
a magic <T>
I don't understand?
I want to be able to have specify a Component as an argument in my plugin
so the client knows it's there
and that's currently not possible
so like
what if you want to create a /tellraw command but on the proxy
you can message players components already, and you could get a component from the argument directly
Alright, implemented it... will fix it up and throw a PR for anyone that wants to look at it
does velocity have a yaml implementation included?
thank you
i wonder does velocity have way to execute "commands" from code? searching those dispatchCommand, invokeCommand terms on javadocs does not seems to be a thing
i remember this being on the velocity forums somewhere
I wouldn't use the configurate version provided by Velocity, it's a major version behind.
hey! is it possible to write a plugin for velocity that can add additional servers to the network? I'm trying to scale my minigame servers w/ docker but I cant find a way to add a new server to velocity.
yes, there is a method to create a registered server somewhere and register it into the proxy
declaration: package: com.velocitypowered.api.proxy, interface: ProxyServer
and also for unregister
declaration: package: com.velocitypowered.api.proxy, interface: ProxyServer
epic thanks!!
how do you do async stuff
Use the Proxy scheduler
or create your own scheduler
Is there a possibility to use Yaml instead of Toml for configurations?
Believe velocity has it built in
how could i store info inside blocks previous to 1.16?
probably not the right channel
Hello, I don't find a method for broadcast at player with custom perms a message
anyone can help me?
iterate/filter

