#Brigadier Command API
1 messages · Page 3 of 1
Wait is the PR about to be merged?
hopefully soon, yes!
2000nd message
WOMP WOMP
poop
i was waiting for that thumb to get deleted

YAY
But it's broken now?
could u try to show code here actually? That may have gotten lost
Lost?
404 on ur pastebin
mhm
class StructureArgumentType extends CustomArgumentType.Converted<Structure, NamespacedKey> {
private static final DynamicCommandExceptionType INVALID_STRUCTURE_ID_EXCEPTION = new DynamicCommandExceptionType(id -> MessageComponentSerializer.message().serialize(Component.translatable("structure_block.invalid_structure_name", id.toString())));
private static final Set<NamespacedKey> STRUCTURES = StreamSupport.stream(Registry.STRUCTURE.spliterator(), false)
.map(Keyed::getKey)
.collect(Collectors.toUnmodifiableSet());
private StructureArgumentType() {
super(ArgumentTypes.namespacedKey());
}
public static StructureArgumentType structure() {
return new StructureArgumentType();
}
@Override
public @NotNull Structure convert(@NotNull NamespacedKey key) throws CommandSyntaxException {
Structure structure = Registry.STRUCTURE.get(key);
if (structure == null) {
throw INVALID_STRUCTURE_ID_EXCEPTION.create(key);
}
return structure;
}
@Override
public @NotNull CompletableFuture<Suggestions> listSuggestions(@NotNull CommandContext context, @NotNull SuggestionsBuilder builder) {
return SuggestionProviderHelper.suggestNamespacedKeys(STRUCTURES, builder);
}
}
@tacit umbra Was this potentially one of the issues u were talking about
@proud timber So is the issue is that the "%s" isn't being resolved?
Yes
Any thoughts on the message up there and this comment ? Is registering commands during server runtime going to be possible and/or cause that CME message?
Theres basically 0 way to guard it
it's also generally not really worth messing around to do so
Oh and I would really like to request being able to lowercase the command "namespace"
Uppercased "namespaces" for commands are so ugly
Yes fixed that
niiiiiice :)
@neat radish there was some issue with Registry stuff right? Some reason to do the RegistryAccess stuff before this
Oh right eys
that is why I split that bit out from the registry mod API. But I forget what that reason was
oh right, yeah. But doesn't that usually happen in the parse/convert methods? Like that stuff doesn't run during bootstrap ever does it?
Correct
That was the reason you described but yeah i never really thouht it was fully needed
I thought I had a more specific reasion. I think someone actually had an issue with it
Also, it seems there are some issues with the help command, will need to be looked into.
I guess its weird to be able to use Registry.WHATEVER within a method in CustomArgumentType, but not in like a static block or something
that is a little bit weird from an API perspective
These messages (#paper-contrib message) reminded me of this issue: https://github.com/PaperMC/Paper/issues/9808. Is there already a config option that resolves that issue? Or does that issue happen to be resolved by this PR as well?
This should be fixed, I think
This is an issue because console uses the command map logic
(My pr changes that)
Oh yeah, it looks like Brigadier-based-command-API.patch removes a few of the lines Add-Unknown-Command-Event.patch added :P. A little silly how one patch adds lines and another undos the changes.
But yeah, it looks like custom Brigadier commands will correctly pass through the if statement to show the syntax error, whereas Bukkit commands nodes will show the Unknown command message.
I also wonder if https://github.com/PaperMC/Paper/pull/9251 will be fixed as well. Maybe I'll test these issues myself to double check.
Yeah, the first is to reduce patch noise until merging
Is there any schedule for merging this awesome api?
Presumably towards the end of 1.20.6's experimental phase
is that at eta???
Updates to Paper do not have any sort of estimate for when they release, ever. Any and all updates will arrive when they are ready, and the only thing to do is wait for them patiently along with everyone else.
If you think you saw an eta, you're mistaken, There Is No ETA
joo dee
rebased
Updates to Paper do not have any sort of estimate for when they release, ever. Any and all updates will arrive when they are ready, and the only thing to do is wait for them patiently along with everyone else.
@proud timber Not a brig issue, btw
private static final DynamicCommandExceptionType ERROR_INVALID = new DynamicCommandExceptionType(id -> {
return MessageComponentSerializer.message().serialize(Component.translatable("structure_block.invalid_structure_name").arguments(Component.text(id.toString())));
});
You were incorrectly passing your parameter
merged 🎉🎉
🥳
yayyyyy 🎊
Is there documentation for how to create commnads with this anywhere?
not yet
@golden crypt
https://github.com/PaperMC/Paper/tree/master/test-plugin/src/main/java/io/papermc/testplugin/brigtests
Or see Commands docuemntation
The example helps me 👍. I'm guessing there will eventually be something here: https://docs.papermc.io/paper/dev ?
It is available now.
Based on Owen's comment above - making sure old command API continues to work unaffected is the top most priority.
I'm sure that more testing is welcome and appreciated.
Oh lol mb, there Paper's Component differs from vanilla I guess
But 🎉 🎉 it's merged
Given that ArgumentTypes#player() and ArgumentTypes#players() both return a PlayerSelectorArgumentResolver and only differ in the internal implementation, why doesn't ArgumentTypes#player() return a Player instance?
The internal impl returns a list
What the point of it returning a list? Seems odd that every time you only player() argument that you would need to use getFirst or something
because player() and players() use the same argument class
Well yeah, and I understand that this is supposed to mirror Brigadier as close as possible while also supporting vanilla arguments, but given API can make things easier, why isn't this changed to return a single player instance?
Because it would just mean more types to add in the api
There would have to be 2 more interfaces added. Just using .getFirst() is fine
Brig doesn’t really support argument types with generic parameters
So every argument type has to be a type without a generic parameter
Im a bit confused, whats the proper way of registering a brigadier command now?
declaration: package: io.papermc.paper.command.brigadier, interface: Commands
see the javadocs
Thank you!
But I can register multiple command in one eventhandler right? Im asking cause in the test plugin there is one eventhandler for each command
in the test plugin it's registering multiple commands in one handler as well
but yeah
Ah missed that
I saw that someone asked in here about enchantment arguments, just opened a PR that should make that super doable. https://github.com/PaperMC/Paper/pull/10770
Thanks a lot, moved my message to paper-dev as I thought this thread is dead.
Is there something like Multiliterals too?
not sure what that is
I think they are talking about something like these which CommandAPI provides on top of Brigadier https://commandapi.jorel.dev/9.4.1/argument_multiliteral.html
Yes this is what I meant. I wasn't sure if this is command api specific or kinda part of brigardier or minecraft
that's commandapi specific
that looks totally useless
just write an argument parser
would literally be shorter without that
Quick question, is there a fancier way to get a CommandSourceStack instance in listSuggestions than to just cast the result from .getSource()?
Nah. Cause its supposed to be sender agnostic. I think it's pretty safe to just always cast
Alright, thanks 👍
Based on Owen's comment (https://github.com/PaperMC/Paper/pull/8235#issuecomment-1369131980) on the Brigadier PR, I would have assumed that using MinecraftServer#getCommands() to register commands using internals would have kept the commands when reloading using minecraft:reload, however they seem to not exist anymore after executing that command as paper seems to reset the resources field in MinecraftServer with a fresh one. The commands registered using API methods seem to be put back via the lifecycle API and Bukkit commands also seem to be copied over.
I know using internals itself isn't exactly supported here and that there are better alternatives like this API and I could probably use the ServerResourcesReloadedEvent alongside Player#updateCommands() to put the commands back but again, based on that comment I would've thought that commands registered when using internals would still exist after reloading.
Is there something that can be done about this or is that simply the intended behaviour now and I misunderstood Owen's comment?
Intended behavior now
For registering commands you’ll need to use life cycle if you wanna use brig
Alright, thanks for clarifying!
Honestly the brigadier command api is awesome! At first I thought it looked extremely messy and confusing but honestly it's just different is all. Makes you use that shift + scroll lol.
I don't know if I'm doing it "right" but it's working pretty well!
It's exciting to think just how plugins are getting closer to mods. Thank you to all of the paper team for your hard work! 😄
You gotta turn off that 8 space continuation indent…
How?
IntelliJ editor -> code style
Then maybe Java, idk. But it’s called the continuation indent
As opposed to the “normal” indent
YO! That is so much better. Thank you so much!
Settings -> Code Style -> Java -> Tabs and Indents. Changing continuation indent to 4 makes a huge difference
Glad you’re enjoying it! 🙂
btw something that I've noticed: brigadier declarations "registered" with CommandRegisteredEvent (yeah yeah I know, it is deprecated, I'm migrating to the new API rn) do not have autocomplete working
(actually now that I've noticed all declarations don't work, not just autocomplete, the commands are still executed correctly tho)
but at least migrating to the new API is going well: I just needed to replace the Mojang packages with Paper packages, replacing the registering stuff with the lifecycle API and it worked (and now autocomplete works again) 
Is this a proper way to go about creating custom argument types?
https://pastebin.com/tDQjSyQ1
In this case, EntityInflictor is just an object that holds an entity which is obtained using ArgumentTypes.entity().
You basically create an "argument" class that implements CustomArgumentType.
Then you create a "resolver" class that implements SelectorArgumentResolver.
Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set period of time.
Implementing custom argument type is the way to create custom arguments
I’m not sure what you’re asking, you seem to have what you need?
It works as expected. I suppose I just wanted to make sure I was doing it "right".
It looks like you can use the CustomArgumentType.Converted
Since you are just directly using the native type to parse it
Oh, I see. Thank you!
I was wondering, is there an "official" way to tell if a LiteralCommandNode in the NMS dispatcher (From MinecraftServer#getCommands()) came from a Bukkit command? Previously, if node.getCommand() instanceof org.bukkit.craftbukkit.command.BukkitCommandWrapper was true, then node was a command wrapped from the Bukkit CommandMap into Brigadier's CommandDispatcher. I'm currently looking for a way to replicate this check after the internal changes from this PR.
What's the usecase?
@golden crypt Check BukkitCommandNode
Compatibility with old API meant for Spigot. The CommandAPI has a feature for unregistering commands. With the two separated Brigadier dispatchers on Spigot, unregistering commands added by other plugins using Bukkit API required extra work. Detecting which commands were added by Bukkit also meant that the CommandAPI could offer the ability to only unregister commands added by the Bukkit API.
So, since currently the CommandAPI supports both Spigot and Paper in one jar, it is possible to run CommandAPIBukkit.unregister("luckperms", false, false) for example. This is supposed to unregister commands with the name "luckperms" that aren't added by Bukkit. Currently on Spigot I can tell which commands are from Bukkit, so the command from the LuckPerms plugin still exists. On Paper I have not yet implemented this check, so it acts differently and just removes all "luckperms" commands no matter where they came from.
So not really a good reason, just I could do it before.
Hm, yeah looks like I can do something similar to before, just a different class :P
Yep
Is there a dependency published for paper-server? Like with Spigot you can access the craftbukkit and NMS classes using org.spigotmc:spigot:1.20.6-R0.1-SNAPSHOT (https://repo.codemc.io/service/rest/repository/browse/nms/org/bukkit/craftbukkit/1.20.6-R0.1-SNAPSHOT/). Is there a similar dependency I can use to access BukkitCommandNode? Or is the only option to use reflection?
No, because we cannot publish such a thing
if you want to access internals, you'd need to use the gradle userdev plugin
Alright, makes sense (though sidenote: now that I think about it, I am confused how it's possible to download a jar containing NMS classes from here https://repo.codemc.io/service/rest/repository/browse/nms/org/spigotmc/spigot/1.20.6-R0.1-SNAPSHOT/1.20.6-R0.1-20240518.014822-2/).
Unfortunately, the CommandAPI project is currently maven based, so I suppose direct access isn't currently possible.
Thanks for your help! Saved me a lot of time looking through this myself.
There was a community plugin for maven, unsupported by us, however
and they're just shipping jars against mojangs EULA
Also a GPL license violation, the reason the DMCA takedown happened
@neat radish so I think CommandSourceStack needs to point to using the executor more where available
as well as using the location instead of the senders location
how best to do that? To make it the default to automatically support the /execute command as much as possible
needs to point to using the executor more where available
What does this mean exactly here?
You have the command sender and the command executor
The sender actually typed the command, but the command executor is the entity as who it is executed
And Machine Maker is suggesting, I think, to use the executor rather than the sender for certain things
Idk what that entails precisely but I'd match vanilla as much as possible
I think I've mentioned that a few times, you have to go out of your way to support the executor right now. The obvious/default way of doing things ignores them and since the API for getting the executor is nullable it's annoying to deal with
@Override
public @NotNull <S> CompletableFuture<Suggestions> listSuggestions(@NotNull CommandContext<S> ctx, @NotNull SuggestionsBuilder builder) {
Player p = ctx.getArgument("target", PlayerSelectorArgumentResolver.class)
.resolve((CommandSourceStack) ctx.getSource()).getFirst();
}
Is this sort of behaviour unsupported- Building a list of suggestions based on other command arguments?
I keep getting "No such argument 'target' exists on this command" when that command does in fact have Commands.argument("target", ArgumentTypes.player()). The player argument is also before the custom argument that is trying to get the "target" argument.
brig might not parse arguments as its computing suggestions
that'd be a brig limitation (a reason to use a more robust command framework)
This shouldn't be a Brigadier limitation. The previous arguments in a command should be accessible when completing suggestions. A framework like CommandAPI is able to allow suggestions to depend on previous arguments because it is possible to pull those values from Brigadier.
So I'd guess there's something weird with your code? Are you able to share the full command or something that reproduces it?
Oh, hm... I'm tyring it myself and it is currently not working. So maybe something with Paper?
Hm, the command added by Paper to the Brigadier dispatcher does indeed look curious. So yea, it seems to me something about how Paper is getting its commands to work is making it impossible to get previous arguments inside the suggestions provider.
For reference, I'm using a command like this: https://pastes.dev/RxLcEK1kzG
Ooooohhhh, wait, nevermind.
nevermind as in it is a brig limitation?
This is a silly quirk in how Brigadier works. I made a bug report about this in their repo because I thought it was strange behavior. (https://github.com/Mojang/brigadier/pull/142#:~:text=I also thought it was weird that this example test for suggestions failed%3A). When a command goes through a redirect, it splits into a child context. When executing the command, Brig gives you the child context, but when suggesting the command, Brig gives you the original context.
The way Paper registered my command, the /test I was typing in gets redirected to the /bukkittestplugin:test node. That's where the redirect comes from, invoking this strange behavior.
So, in order to access the arguments, you have to get the child of the given context, which actually contains the arguments. In the command I sent, to get the Player target, I can do this:
Player player = context
.getLastChild() // Get the child context that actually holds the args
.getArgument("target", PlayerSelectorArgumentResolver.class)
.resolve(context.getSource())
.get(0);
So, while it works weirdly, you should be able to get the arguments while completing suggestions if you use CommandContext#getLastChild. I was a bit thrown off since I didn't expect Paper to insert a redirect into my command, but it seems reasonable. I'd also err on the side that this is intended Brigadier behavior given the lack of a response on Brigadier#142.
Ayo, thank you so much for looking into this! You saved me a large rewrite.
I think Brig is more of a "source available" thing than open source
They don't really care about the framework unless they need to for Minecraft
Yea, tho I suppose if they’re not changing anything then everything is “working as intended”
Hey so I have an argument that ultimately returns an adventure Key (from what I've seen, Paper is moving towards adventure keys so I've replaced most of all of my custom stuff to used Keyed and Key from adventure).
However, I want to make it so the user can input the argument without needing to explicitly put the separator :. If no separator is inputted, then the namespace will default to the plugin's namespace. Is that possible with Brigadier? There doesn't seem to be any string argument types that allow any and all characters.
public class CruxKeyArgument implements CustomArgumentType<Key, String> {
@Override
public @NotNull Key parse(@NotNull StringReader reader) throws CommandSyntaxException {
return Crux.key(getNativeType().parse(reader));
}
@Override
public @NotNull ArgumentType<String> getNativeType() {
return StringArgumentType.string();
}
}
I tried doing this but this makes it so you can't put the separator, : since, for example, if I input one:two, it only returns "one".
maybe try using the ArgumentTypes.key() as the native type, and parse it yourself in parse
key() and namespacedKey() will use the minecraft namespace by default so you'd have to parse it yourself if you want your namespace as default
This
That works but as you're typing the command, it acts like something is wrong and therefor doesn't show the next parameters when you hit space.
This is the new code. It is getting the string properly and everything now, it just thinks there's an error while typing.
public class CruxKeyArgument implements CustomArgumentType<Key, Key> {
@Override
public @NotNull Key parse(@NotNull StringReader reader) throws CommandSyntaxException {
String string = readString(reader);
Bukkit.broadcastMessage(string);
return Crux.key(string);
}
public String readString(@NotNull StringReader reader) {
final int start = reader.getCursor();
while (reader.canRead() && reader.peek() != ' ') {
reader.skip();
}
return reader.getString().substring(start, reader.getCursor());
}
@Override
public @NotNull ArgumentType<Key> getNativeType() {
return ArgumentTypes.key();
}
}
Hm, I had hoped changing the native type to ArgumentTypes.key would've solved that for you. Mabye you need the actual native type? ((VanillaArgumentProviderImpl.NativeWrapperArgumentType<?, ?>) ArgumentTypes.key()).nativeNmsArgumentType();
(bit cursed if true)
public @NotNull ArgumentType<NamespacedKey> getNativeType() {
MaterialArgumentType example from the paper repo
Yeah this seems funky..
I don't quite understand. The MaterialArgumentType doesn't look like it has anything useful for this case. Changing from Key to NamespacedKey doesn't fix the issue either.
Do you allow other namespaces? Or should the namespace always be your thing
I allow all other namespaces
If it's always your thing just use StringArgumentType.word
Ah okay
That's the tricky part it seems
It shouldn't be hard at all
That was my first thought until actually trying to do it lol
Given that the client complains, there's something going wrong with ArgumentTypes.key()
It's weird because ArgumentTypes.key() works by itself. But when creating a custom argument that uses it, it's like you can't use : anymore (at least in the client's eyes)
This is how they're implemented https://github.com/PaperMC/Paper/blob/master/patches/server/0975-Brigadier-based-command-API.patch#L1274-L1282
That's cursed
Maybe an implementation mistake somewhere
Both tests in https://github.com/PaperMC/Paper/tree/master/test-plugin/src/main/java/io/papermc/testplugin/brigtests/example use CustomArgumentType.Converted
I also use that in my plugin
And that works, and I assume the same for the tests
So it's likely that CustomArgumentType.Converted works but just CustomArgumentType doesn't
Just CustomArgumentType should probably also have been tested...
@lusty sierra probably best to open an issue
I went ahead and tested this code with a custom key argument and it seemed to work fine on 1.20.6:
@Override
public void onEnable() {
getServer().getPluginManager().registerEvents(this, this);
getLifecycleManager().registerEventHandler(LifecycleEvents.COMMANDS, commands -> {
commands.registrar().register(
Commands.literal("test")
.then(Commands.argument("someKey", new CustomArg())
.then(Commands.literal("anotherLiteral")
.executes(commandContext -> {
commandContext.getSource().getExecutor().sendPlainMessage("The key in question: " + commandContext.getArgument("someKey", Key.class).asString());
return Command.SINGLE_SUCCESS;
})
)
).build());
});
}
private static class CustomArg implements CustomArgumentType<Key, Key> {
@Override
public @NotNull Key parse(@NotNull StringReader reader) throws CommandSyntaxException {
int start = reader.getCursor();
while (reader.canRead() && reader.peek() != ' ') {
reader.skip();
}
String key = reader.getString().substring(start, reader.getCursor());
if (key.indexOf(':') == -1) {
return Key.key("custom", key);
} else {
return Key.key(key);
}
}
@Override
public @NotNull ArgumentType<Key> getNativeType() {
return ArgumentTypes.key();
}
}
The client handled the key argument like expected
Interesting
Currently BasicCommand registration is missing a parameter for the permission; would you prefer a builder, like in https://github.com/PaperMC/Paper/pull/11046/files#diff-b0cb919804c1a0443199a801b663fa19ddbc30fb19ea4bf8d9a1cee938ab69f3R559, or to instead have a default canUse(Player) method or similar in BasicCommand, paralleling requires in proper brig registration. adding more params to the existing register methods is a no-no because they will get overcrowded
or a permission string getter instead of canUse to keep it simple, have the full capabilities only in the brig builder
Would it be possible to do both, and have the permissions method delegate to a requirement? So somewhere the implementation would look like:
// Command is acessible by default
Predicate<CommandSender> requirement = sender -> true;
withRequirement(Predicate<CommandSender> requirement) {
this.requirement = this.requirement.and(requirement);
}
withPermission(String permission) {
this.withRequirement(player -> player.hasPermission(permission));
}
BasicCommand is an interface, so it has to be a method where a return value is used
though that's what the builder PR looks like https://github.com/PaperMC/Paper/pull/11046/files#diff-b0cb919804c1a0443199a801b663fa19ddbc30fb19ea4bf8d9a1cee938ab69f3R592-R603
Ok, so something like?
interface BasicCommand {
default String getPermission() {
// Null means no permission set
// Or maybe Optional would be better
return null;
}
default boolean canUse(CommandSender sender) {
return true;
}
}
// When creating CommandNode
BasicCommand command;
Predicate<CommandSource> requirement;
String permission = command.getPermission();
Predicate<CommandSender> canUse = command::canUse;
if (permission == null) {
requirement = source -> {
CommandSender sender = source.bukkitCommandSender();
return canUse.test(sender);
}
} else {
requirement = source -> {
CommandSender sender = source.bukkitCommandSender();
return sender.hasPermission(permission) && canUse.test(sender);
}
}
LiteralArgumentBuidler
.literal(commandName)
.requires(requirement);
hmm having both might be confusing, but could work too
so in any case, you'd prefer one or both methods there over the pr?
Just an alternative idea. Imo if the BasicCommand is basically a Spigot command then just a permission seems reasonable in most cases, but I use full Brigadier commands anyway.
is it possible to allow any character in single string arguments (word not greedy)
by default only alphanumeric values are accepted which is kinda stupid
no
ask mojang
Mojang hates non english speakers
a quoted string can accept non-ascii but needs to be, well, quoted
yeah in my case quoted is stupid and totally unintuitive because " is literally an allowed input character
\" 😏
the suggestions would look like shit
i could use key arguments to support colons but !"/ are expected inputs so what else could i use
and putting the argument at the end is not really an option (so it can be greedy)
okay well... doesnt look that bad
Relevant issue if you're curious~ https://github.com/Mojang/brigadier/issues/103
I wonder if there is a Minecraft bug report for this to possibly get it classified as a gameplay issue and not a Brigadier API issue...
there is some bug
@golden crypt https://bugs.mojang.com/browse/MC-97885
This is because of brig
So I found out that using the Key argument directly works but once you try getting an object from the key, that's when it produces the issue. For example, let's say you have something like this:
public abstract class CruxKeyedArgument<T extends Keyed> implements CustomArgumentType<T, String> {
public @NotNull T parse(@NotNull StringReader reader) throws CommandSyntaxException {
//CruxCmdArguments.CRUX_KEY is basically the same CustomArg class that you sent.
return this.parse(CruxCmdArguments.CRUX_KEY.parse(reader));
}
public abstract @NotNull T parse(@NotNull Key var1);
public @NotNull ArgumentType<String> getNativeType() {
return StringArgumentType.string();
}
}
And you extend it:
public class SomethingKeyedArgument extend CruxKeyedArgument<Something> {
@Override
public @NotNull Something parse(@NotNull Key key) {
//get it in some way
}
If you try using the SomethingKeyedArgument directly, like so:
Commands.argument("something", SomethingKeyedArgument),
it produces the issue.
Seems like a weird issue, I don't know. At least it can be fixed by approaching it differently:
Commands.argument("something", CustomKeyArg)
.executes(ctx ->{
Key key = ctx.getArgument("something", Key.class);
Something something = //do the parsing here instead of within the actual argument itself.
})```
It appears my brain decided to take a long vacation. The reason the error was present was because CruxCmdArguments.CRUX_KEY was still using CustomArgumentType<T, String> and StringArgumentType.string() when it should have been using CustomArgumentType<T, Key> and ArgumentTypes.key().
So does it work for you now or no?
Yeah it's working now
Is there no way to use a CustomArgumentType to parse the argument based on the command context? Like, for example, getting data from the player using the command.
Nope, brig doesn’t support that. That’s why lots of the built in argument types are “resolvers” where you have to pass the source to get the value
Technically, it is possible to achieve this by extending the ArgumentCommandNode class, though https://github.com/Mojang/brigadier/pull/144 makes that a little weird to pull off. Otherwise, yeah, having your ArgumentType return a Function<Player, T> or equivalent and passing it the previous context in your suggests or executes should always work.
Contributing to Brigadier is a lost cause
Alright. Thank you!
Brigadier is a pretty nice command framework in general though. So thanks to the Paper team for opening it up for us (:
i am missing methods to define my own namespace fallback for command arguments
The argument does not support that by itself, but you can work around that limitation by using a custom argument
So something like this
is there some way of checking whether a user has access to any of the subcommands without reperforming all of the checks?
there are to many conditions and commands but i dont want to add a permission to the root command or smth
dont think so lol
requires only returns the command source stack so i have to do all checks right ?
the subcommand nodes can have their own requirement predicate, not sure what you mean otherwise
i know they do
but the root command gets suggested even when no subcommand can be used
Well, yeah, because you don't have a permission on the root command blocking access
So I guess I'm saying you need a requirement predicate on the root that ORs all the requirements for the subcommands, like you feared
what you'd do is make all of those perms have world.command as a child perm
smart call
Could maybe also put all your subcommands in a list and loop over each of them to check permissions and add them as children to your root.
holy thats even smarter
so, having access to world.command.list would grant access to world.command
i named the permpack for all commands
worlds.commands is that a too vague distinction in your opinion?
electroniccat's good suggestion aside, why does it matter that someone can see the root command but not execute any of its children?
I wouldn't have cared about it 🤷♂️
no reason to clog your tab complete if you dont need to
"clog" as if one command makes a difference when you have a million other plugns with each a million other commands
Anyway I don't think it's worth a discussion
All my plugins only expose their commands to users with the required permissions or conditions
A new user without any permissions will see about 4-8 commands based on the server they are connected to
I even made a plugin just to add a permission to the LuckPerms root command if a user can't use luckperms
I absolutely hate it when plugins dont properly use permissions for their commands
For example essentials exposes (or at least did at some point) all of its commands even if the player has no permission to use them
A new user will have no clue what they can and can't do if that is the case
Question, does this api respect aliases in commands.yml? or are there other ways to achieve command overwriting?
[00:51:26 WARN]: Could not register alias warp because it contains commands that do not exist: warps:warp $1-
[00:51:26 WARN]: Could not register alias setwarp because it contains commands that do not exist: warps:setwarp $1-
trying to overwrite some of essentials commands, but logs claim the commands are non existing
just disabling the commands did the trick:
command-block-overrides: []
ignore-vanilla-permissions: false
aliases:
warp:
- []
setwarp:
- []
Pretty sure essentials is using Bukkit commands
@vernal fractal before I dive into this... is there a potential issue with CommandAPI (since the brig changes) where running /minecraft:reload "erases" plugins registered via your lib? One of my plugins triggers such a reload, and plugins that used CommandAPI suddenly don't have their commands anymore. I'll dive into it if you aren't sure.
Yea, kinda. Since the CommandAPI puts commands directly into the Brigadier dispatcher, when Paper reloads it doesn’t seem to persist them automatically. The CommandAPI is supposed to hook into Paper’s ServerResourcesReloadedEvent though to put its commands back (added in this commit).
isnt it possible to get a parsed argument from the context within a suggestion provider?
iirc velocity can do it
i can only access the context provided by the getSuggestions method
is there a way to modify this unknown command message when a player attempts to use a command that they don't have permission to use?
I know there is the UnkownCommandEvent I could listen to, but is there a way to do it when registering the command via the new command api?
No
if you do change it, a lot of server owners will just use something like pl hide or whatever to effectively revert it to the default message anyways
wouldnt really call that a reason to not have it. not all servers want that, nor does that really have customization over each different commands deny message.
Everything is handled by the dispatcher
Adding rejection messages requires us to basically excessively hack brig just to support that
yeah, not saying it should/shouldnt be added... having to hack brig is a valid reason to not add it. The reason of "oh some servers install this 3rd party plugin to change the output anyways" isnt a valid reason
I feel like in pretty much every situation, you want commands they don't have permission for to not be even known to the client and so that message makes perfect sense
if you have some conditionally-allowed command, clients should just always have permission and then do a separate check on whatever that condition is within the execute method
I can somewhat agree with that, for my specific usecase I'm using luckperms contexts to give a player a permission based on if in specific griefprevention claims. So its just not intuitive for the player where in specific claims they get an "unknown command" message instead of a no permission message.
Having to add an extra checks ontop of using luckperms contexts doesnt seem right
Yeah, thats a good work around, a lot better than using the unknowncommandevent. Not perfect, but i'll make do
`
On a different note. What are the thoughts on adding more info the BasicCommand interface, such as description, label and aliases.
That way to register a command its as simple as:
commands.register(new FunCommand())
brig doesn't have some of those concepts
and trying to pretend that they exist just presribes us to bukkit-isms
i thought the whole point of the BasicCommand was to provide a similar way to bukkits implementation. (as described on the docs).
And I dont think this wouldnt be some hack or anything, something as simple as a couple of methods that need to be overridden
feature creeped
The goal is to provide a minimal basic interface to register basic commands without having to learn brig as a means to quasi deprecate the legacy bukkit command map
dont see how this is a feature creep. u could argue the entire basic command is a feature creep
it is
that has been argued
its the middle ground of "we know brig is complex, here if you wanna hack something together real quick" vs "pls use a proper framework for brig or learn brig yourself"
vanilla has 0 concept of labels or description afaict
well yeah, but we're not vanilla, this is paper
again, this is a minimal abstraction over brig
That information does not exist on the brig nodes
well labels/desriptions exist with or without this
ur still having to implement them
no?
if i just supply the literral command node, what is shown up on bukkits /help then?
is it just not there?
i figured it was just there with a blank description, but i haven't tested it
probably a blank description as vanilla does have descriptions for commands
yeah, but paper (technically bukkit) is adding it.
within the legacy bukkit system
but that is all going to be blank strings
There is literally interest in our part hacking brig to add such things
if it was up to me I'd remove bukkits help command right now
thats a whole other discussion
well, if "descriptions" and "labels" dont exist, aliases do, (redirects) so seems valid to me that those should be apart of the basic command
do custom brig commands show up as mojang provided?
i can test it right now
beat me to it, yeah its just blank
the string is hardcoded for the mojang commands in the legacy bukkit wrapper class
maybe should add a "A plugin provided command." if no description given
better than it being blank
huh PluginVanillaCommandWrapper extends VanillaCommandWrapper
clearly this means we need to expand on the o.b.help API instead 
I think I've seen like 2 plugins interface with that API, ever
ah, so, the register method lets you put in stuff for the legacy command wrapper
default @Unmodifiable @NotNull Set<String> register(final @NotNull String label, final @Nullable String description, final @NotNull BasicCommand basicCommand) {
obviously we need help2.yml, as well as keeping help.yml for legacy reasons
finally someone making some sense
@neat radish how do you think the resource_or_tag and resource_or_tag_key argument types should work? They directly use the Either type
we have all the needed types to add those to the ArgumentTypes API
one is an Either<Holder.Reference<T>, HolderSet.Named<T>> and the other is Either<ResourceKey<T>, TagKey<T>>
actually, don't wanna do the first one cause it would require an ugly T extends Keyed in a spot one shouldn't be
I cant find the example admin command anymore
did you delete it?
^
it still exists in the test-plugin folder of the repo
@neat radish how tricky would it be to implement a way to convert an nms ParseResult<CommandSourceStack> to the api one? There's a couple places where exposing the parsed command might be useful
Do you mean ParseResults?
Cause lowkey that should already be exposed? Like in event.registrar().getDispatcher().parse
well I mean an already parsed one from vanilla
I'm looking through open feature requests, and noticed one to format whisper messages, and realized that is possible via AsyncCommandChatDecorateEvent, but there is no context about what command was run
if we could convert the existing nms ParseResults into the API CommandSourceStack type, we could add that to the event and then the command should be known
Lowkey it might just kinda get involved, depending on if we want to make it an immutable view or whatever. Would need to do alot of node unwrapping/wrapping
those node wrapping/unwrapping get cached tho right?
🤔 CustomArgumentType.Converted.html#convert should probably not only allow native argument types, but also other Converted types
That's how Quilt does it too
Not sure what you mean there
Quilt is also a low level thing so mods can add custom types natively in there
At least in terms of what that would actually do given that the underlying type needs to be supported by brig, nesting them for conversions makes very little sense imho
Since Converted types (and CustomArgumentTypes in general) would ultimately rely on native types, you could recursively convert the type until it's a native type
NeoForge uses this https://github.com/neoforged/action-pr-publishing/tree/main
is it possible to unregister a command after its been registered via the lifecyclemanager?
do a /minecraft:reload or Server#reloadData and don’t register the command again when the event fires
I'm registering the commands in the onEnable section as listed on the docs. The minecraft reload, nor the reloadData unregister the command I registered, so not sure if i follow this.
well you are using the event right? the event re-runs during those reloads, so itll just run the event again
so if nothing changed, the command will be re-registered
i think i follow
it's all making sense now, I guess some feedback would be maybe for reloading data via api, would be to specify what should be reloaded. for example, if we wanted to just reload commands, we wouldnt have to reload everything else, (tbh idk apart from datapacks, and i guess now commands what all gets reloaded from it)
That… isn’t simple. Lots of things depend on other things. Like if you reload only tags, you also have to reload commands I think. And trying to map out those “dependencies” isn’t a good idea. Just don’t be reloading too often
since 1.21.2 nms Entity is no longer CommandSource and CommandSource.NULL is used for creating CommandSourceStack. How would this api handle that?
Is it possible that there is an thread sync problem using by the new command api?
elaborate please
In my clan system it is sometimes the case that when you transfer a clan, for example, the ranks are not displayed correctly and are not recognized correctly by parts of the system. For example, the /clan command in a GUI indicates that you still have the Owner rank. However, it is displayed correctly via the /claninfo command. Subsystems are also affected by this. However, the whole thing is thread-safe via the concurrents. The individual clan information is also managed centrally via a single manager that can be accessed by all systems. I therefore cannot explain what the problem could be.
"in a GUI"
brigadier just deals with parsing + dispatching
anything display related is basically 100% on you
the only caveat would be that you can't change the command tree at runtime, i.e. removing/adding things based on perms, without resending the entire tree
Okay thank you
Potentially off topic, can we get some kind of API to check if a command is safe to execute async? Allow commands to declare themselves as being able to run asynchornously which will default to false.
The use case for me is I make a couple plugins that allow you to execute commands under certain conditions, one of them is a simple conditional and timed command executor plugin and the other is an anticheat that allows you to execute commands on flags.
Performance can get really awful for running tons of commands on the main thread whose implementation is often already thread-safe or could be made thread safe with very little modification.
This will not be implemented. The command system is not made to be invocated async, and if you really need to, you should just have a command delegate logic to another thread.
Yeah I do that in my code the problem is my plugins execute arbitrary commands including from other plugins
There's no way I can know that calling /aopetihe defined in the config for a server by one of my users can be invoekd async or not
Then you should ask those plugin developers to expose API that allows you to interface with it async.
For every plugin?
Executing a command from another thread is unsafe regardless of what the command does
that all use diffefenrt apis?
Someone on the main thread could be registering a command at the same time
No...? My own command support this behaviour?
If you are executing another command async that you did not make, it does not mean that its all the sudden thread safe.
I'm saying it doesn't matter if you were careful in your command implementation, the command machinery itself isn't thread safe
yeah which is why I bypass paper in this regard
I was hoping that could change
Unless you bypass brigadier that doesn't really help
I do actually
I went as low as I could go
following the stack trace
but anyways
that's a side note
I don't think we're on the same page as to what I"m asking.
I have a plugin is to have config.yml where you can go
whenSomeEventHappens:
- /somearbitraryCommand
- /anotherArbitraryCommand
I would like to be able to go
String command;
if (Bukkit.getServer().getCommandCanBeExceutedAsync(command)) {
Bukkit.executeCommandAsync(commandSender, command);
} else {
Bukkit.dispatchCommand(commandSender, command);
}```
If I were to implement a PR adding support to execute commands like this, would you accept it?
For Bukkit Commands its pretty simple, add an annotation or something on top of OnCommand() to mark it as executable async
For Brigadier Commands something similar is already done in Cloud with command executors, though I'll probably take a different approach.
Point is I'm fully willing to implement this all myself and make it work. My only question is if you would be open to merging it (@peak charm @neat radish?) once I'm done because there's no way this will be adopted if it doesn't make it way into Paper.
Relying on this is an implementation detail, Server#dispatchCommand not using brig will be removed in the future as generally its an old implemenmtation.
Command execution is not supported async, period.
So sadly this will not be adopted.
Making brig support async commands is too invasive and not really a goal in Paper.
Especially when plugin devs already mostly delegate expensive commands async anyways
Brigadier doesn't store such context and it's generally not something that we're inclined to hack into brigadier to provide support for unsupported behavior
if you wanted async dispatch support, you would need to get such support and annotation added to brigadier, and I really doubt that they're interested in that either
Even then I would expect like 0.1% of plugin commands to actually be thread safe, unless all they do is send a message
Also how would async commands work with datapacks and command blocks, those expect a return value directly
Also, you should know that making something "async" doesn't autmatically fix all problems and make the stuff more performant. It is more worthwhile for people to fix their performance leaks than to try to offload the work
If your command takes 20 ms to run, putting it async will still lead to terrible performance — it just wouldn't affect the main thread as much
Furthermore, unless you are genuinely running into performance issues, there is no need to over-optimize your code. Modern day computers are really fast, you know?
Async is great for http requests or file io. But that should be handled by the command creator already anyways
Add a material argument
Item and BlockType will do that
oh very good
thank you
(they already do btw)
well but what if I need both
wait an item registry contains like stone right?
Yes
oh ok then nvm
You can also just have one branch which has the item one and another which has the block one
They're two seperate distinct things, Material is a blatently bad system which consistenly leads to errors because it blindly confuses those concepts together which no longer exist
Are there any plans to deprecate the material enum in the future?
I think if Mojang will make custom registries for items & block (meaning fully custom items & blocks), Using ItemType and BlockType separately would be a useful thing
That's why ItemType and BlockType exist
Oh very well then
Items and Blocks are already distinct types in vanilla, thankfully many items are blocks and so they match up 1:1, but then there are the fun cases where there is no alignment there; and generally, trying to pretend that they exist in one happy bundle like they did 10 years ago is a constant source of headaches with the API and plugin devs not understanding that carrots and carrot are not the same thing
Not sure if this is related but thanks to whoever made CommandNode requirement field public ❤️
.requires is a thing yk (and getRequirement)
brigader crash tho hoo snow
wat
Send logs into #paper-dev
nonono im not saying i have issues
im joking around
there used to be a crash for brigader
but its fully patched now
Tbh @neat radish, we might just be able to close this post now since this is getting un-experimentaled soon anyways and I believe there is no more constructive feedback to be given anymore
When will is it planned to put it out of experimental?
We are currently waiting on that
afaik it already has been: https://github.com/PaperMC/Paper/commit/371a42256737157387ac492dd871884601da2d46
Yep
what's the diffrence between brigrader command API vs regular command registration from bukkit?
the brigadier API is basically a fairly low level means of accessing mojangs command system
the bukkit command system dates back from when craftbukkit replaced the vanilla command system, now it's just in some weird state of basically trying to mirror the vanilla command system
it's a lot more primative but somewhat easier from a beginner perspective if you don't want a lesson on trees
It gives you proper client-side completion of certain arguments, like number ranges, resource locations, quoted strings and whatnot, also telling the client beforehand what goes where
Using Brigadier gives your command users a much better experience using your command
There are downsides also though. Your commands must more strictly follow mojang's command style to get these enhancements
The very popular example of StringArgumentType.word() being incredibly restrictive in terms of which characters you can enter
is using brigradier harder? if so how much?
Well, it's just more technical
More "fancy sounding classes"
Bukkit commands is just a String array
does it work w/ folia
Yes
is there any good examples of brigraider command
I mean, the docs should have you covered in terms of learning it: https://docs.papermc.io/paper/dev/command-api/basics/introduction/
And here is a direct comparison between bukkit and brigadier commands: https://docs.papermc.io/paper/dev/command-api/misc/comparison-bukkit-brigadier/
(Seen with code)
bruh so complicated
(It's really not that complicated)
As I said, it's just a whole bunch of complicated sounding classes
Once you understands its essence, it is incredibly easy
branching is cpmplicated
Not much more complicated than nested switch statements 
(Which is basically what Bukkit commands are)
should I stick w/ bukkit or go to brigradier
I heavily suggest that you learn Brigadier. If you do not feel comfortable with plain Brigadier, feel free to use a command framework
Like CommandAPI
Brigadier. Much nicer user and developer experience.
but so hard, uhhh
Bukkit commands are a legacy system
Use a command framework
Like commandapi: https://docs.commandapi.dev
is there any youtube tutorials
No, and that's good, because youtube tutorials gets outdated way too quickly
Reading is a developers best skill :3
Sure, what exactly are you having issues with rn?
uh, I'm trying to send a reosurcepack in the config phase of the API, but I don't know how to do that
if you can't answer this queston, here's another thing I need help with
the brigraider command API. I want to change my command system in my plugin to use that API
btw I sent friend request
I don't give DM support, sorry
oh
So what parts are you having trouble with?
how do I migrate to the brigraider API. Here's my old implimentation: https://pastes.dev/QPCMeSgklG
I want to move to using brigraider api
i'm reading the docs
For the permission, you should use a requirement:
You can display the help message by putting a .executes method onto your root node:
Commands.literal("gem")
// ....
.executes((ctx) -> sendHelpMessage(ctx.getSource().getSender())
.build();
Since your first argument is a player, you can add a player argument type and resolve that inside your executes:
- https://docs.papermc.io/paper/dev/command-api/basics/arguments-and-literals/#arguments
- https://docs.papermc.io/paper/dev/command-api/arguments/entity-player/#player-argument
Commands.literal("gem")
.then(Commands.argument("target", ArgumentTypes.player())
// at some point later
.executes(ctx -> {
Player target = ctx.getArgument("target", PlayerSelectorArgumentResolver.class).resolve(ctx.getSource()).getFirst();
// ...
});
);
Your second argument is a number, so I suggest you do the same with a number argument type:
For the final argument, which seems to be the gem type, I would suggest you use multiple literals:
Alternatively you could also just use a word string argument type and add suggestions:
wait, this actualy might be better than bukkit
That's all the spoonfeeding I will be giving for today. I am tired and gotta sleep. I wrote the docs very verbosely, so I hope you will take your time reading them 
because you can set subcommands to require permissions
I will
Yeah ikr
thank you so much
Yw
bye
goodnight
