#Brigadier Command API
1 messages · Page 2 of 1
that's the instance of the custom argument type that wraps the nms argument type
a custom argument type can be double wrapped
Yes, but wouldn't putting that check still work?
These are custom argument types still (the vanilla arg providers)
ok, yeah. that should work then still
Also, I think we should have a way for plugins to "construct" custom argument types from a regular brig argument type and a function converting them to a type. I think that allows further platform-agnostic abstraction
you can take a plain brig custom argument type, and create a paper-custom one without dealing with the inheritance stuff
Hmmm, I think I agree here. How would somethin liek that look tho?
I mean basically we just have a simple impl of CustomArugmentType that takes an extra Function<Primitive, Type> function, then the convert method uses that function
and then a static method on CustomArgumentType to create it
@tacit umbra If you wanna whip something up for that, feel free. I've pushed the validator fix.
we should expose the StringReader in the parse method as well actually. it is useful for creating better exception messages, just look at how SimpleCommandExceptionType is used
expose it as immutable tho
also might be good to add methods to the MessageComponentSerializer to more easily create the exception types? or at least the inner Function interfaces
Didn't quite think of that. I didn't realize that the string builder had exception methods like that.
I agree
What about this?
Btw I figured out why my suggestions were all wrong, it's because I didn't know that Material was an enum class, and my plugin handles enums differently
Cause it’s not used for anything on the server really.
Well it's used for validating the argument type
And it gives insight in to how the argument is used for people looking through the code
And also there is no downside of allowing it
virtual dispatching is expensive 
The validation happens way earlier than when commands are registered, so it’d have to be delayed or ran again after all plugins have loaded.
actually, command validation isn't run at all on production servers
Ok @neat radish talk me through the handleSuggestions method we have in CustomArgumentType. Is there a way we can avoid that? Cause you have to override 2 things if you want to do suggestions instead of one.
How are the vanilla argument types checked, then? Also, it is?
Honestly, I never really went in depth for that system. If that needs to be removed, that is fine.
the validation is only ran when you set SharedConstants.IS_RUNING_IN_IDE which is what I assume mojang devs set when developing
vanilla commands don't need to be validated every time, just before a version release. Cause they don't change randomly
I see, you are right. I misread DefaultAttributeRegistry.checkMissing() for CommandManager.checkMissing() ```java
public static void logMissing() {
Bootstrap.ensureBootstrapped(() -> "validate");
if (SharedConstants.isDevelopment) {
Bootstrap.getMissingTranslations().forEach(key -> LOGGER.error("Missing translations: {}", key));
CommandManager.checkMissing();
}
DefaultAttributeRegistry.checkMissing();
}
That's a bummer tbh, I also could have sworn they did actually check it always. Maybe some versions ago?
we could maybe add support for it, and it'd run validation if you specify a flag so devs could check, but not really concerned with that now, can be added later
Can the getExamples method still be made available or?
well the downside of removing the final is that it could lead to confusion that it actually does anything
well clearly not, cause you suggested that it be overidable to "document" how to use the argument type 🤣
not 100% on it being final. it wasn't originally
what is the usecase for it not being final now?
I don't want it to be not final, documented as not doing anything, and then suddenly it does something. that would be breaking API contract
but if we blocked overriding it, then when it does something, allow it, no contract breaks
Well is it really breaking API if it actually means someone wrote their argument wrongly lmao
no that's not what I mean
If the method is documented as not doing anything or having any effect, that is the API contract for that method
maybe mojang adds some use for it on the server then later
and suddenly the method that was contracted as "not doing anything" does something
if it does nothing, best to not have it, that way if it ever does something, no contract is broken by opening it up to overrides
Sure
But aren't "breaking" API changes necessary sometimes due to Minecraft changing
well generally no, not to our API. but brig isn't our API, its mojangs
But yea this is a small detail anyway, it's fine like this ig
behavior is broken, and maybe methods no longer function, but changing function generally is avoided when possible
Btw I also found the doubly overriding thing a bit weird to allow suggestions
yeah, I'm gonna see if that can be avoided. basically, right now its kind of needed to determine if your custom argument should use the suggestions on the primitive argument type, or your overriden listSuggestions.
One possible solution is to use reflection to see what type on the type heirarchy the listSuggestions method is defined, but that seems hacky.
so if the declaring class for the listSuggestions method on the argument isn't CustomArgumentType, that means it was overriden and should use your custom suggestions
if it wasn't overriden, use the primitive args listSuggestions
When does the primitive argument type ever have suggestions
lots do
EntityArgument
positions, item stack
primitive != java primitive
primitive == native argument type to minecraft
Ohhh those
I was confused with the default brig argument types
Whoops
Mmm yea reflection seems the way to go ig
@neat radish so I'm thinking about the parse() and convert() methods in CustomArgumentType. If we allow overriding parse, therefor allowing the custom arg type to parse manually from the string, it's almost worth splitting out to have 2 custom arg types, once extending from the other
So basically, if you just overrode parse, the only thing the primitive would be doing, would be providing validation for the argument input on the client, but all parsing would be done by the server, is that something we want to support?
then we could have a subtype of that which added the convert method if you didn't want to parse yourself, just convert
I can see a use case for both. It would be more performant for a lengthy argument to fail part way through parsing rather than parsing the whole thing, then converting it to your type and seeing if its valid
At some point I had a similar idea, where custom argument was gonna be an interface where it only provided a argument type that is sent on the client. I think that’s fine, opens it up a little bit more.
that way, we only expose the reader during parsing, and not during conversion. Having the reader during conversion isn't super useful, cause the point of creating exceptions is to show exactly the point in the argument where parsing fails
can't do that if it already has been parsed+converted
// If however we want to handle suggestions ourselves, reference the wrapper.
try {
final Method listSuggestions = wrapperArgumentType.getClass().getMethod("listSuggestions", CommandContext.class, SuggestionsBuilder.class);
if (listSuggestions.getDeclaringClass() != CustomArgumentType.class) {
suggestionProvider = wrapperArgumentType::listSuggestions;
} else {
suggestionProvider = null;
}
} catch (final NoSuchMethodException ex) {
throw new IllegalStateException("Could not determine if the custom argument type " + wrapperArgumentType + " overrides listSuggestions", ex);
}
also @neat radish I'm changing the type of the vanilla argument type wrappers. I don't think they should be "CustomArgumentType" cause they aren't also, that means you can cast them, and get the actual nms argument instance
also, the getExamples method should return the nms examples, no reason not to, and can't do that if we have getExamples final in CustomArgumentType
ok, so I noticed some odd behavior, and the cause makes it kind of unclear how to fix, or if we should fix. Take a look at the demo plugin, specificaly try using the /material <item|block> <key> command, but put an "invalid" namespaced key in, so like /material item diAmond (can't have capitals). The error throw is from the "convert" method of the MaterialArgumentType, and the "key" its converting, is mincraft:di. The vanilla ResourceLocationArgument reads until it gets to an invalid char, but the exception for "invalid arugment" is in the parser, if after parsing an argument it finds non whitespace after. The code doesn't get there, cause the exception is throw in the convert method.
This could be fixed once registry mod API is in, so we can better use the ResourceArgument which represents something in a registry
pushed everything I've done today on it
not 100% sold on the block position argument. You are losing quite a bit of info, like local coords. It is flooring doubles, so you lose precision about the inputted position
@tacit umbra Lemme look through this all here.
Yeah so, I don't think that this is something we should have to fix or whatever. This is an implementation detail in the vanilla argument type, so, I say it works as expected.
Maybe the documentation can clarify that you need to handle some cases like that
Cause see what mojang does for usages of that argument.
Ohh wait
yeah, so maybe we recommend not to create a custom arg type for a "Keyed" thing like this directly, but get the key and then parse it to something in the command execution logic
Are you talking about this too?
well yeah, that error doesn't show up for the custom MaterialArgumentType
like try the command I showed, the error will just be "Invalid ID" and its thrown in the "convert" logic in MaterialArgumentType
Yeah hmmm, but the error is there client side
correct, cause its just a regular resource location argument
rememeber that for keyed registry things, there is actually a "better" argument, the ResourceArgument, but we want the registry mod PR for that, specifically the RegistryKey type
Oh yeah 100%
so I think we just document that if you want a "keyed" argument, the recommended way is to just have a plain namespacedkey argument, and then in the command execution logic, check if that key is valid
that way the error message correctly shows the incorrectly formated key
also instead of NamespacedKey, we should use whatever adventure type there is instead
I added both. Both should exist until we transition more stuff to Key, cause its annoying to have to create namespaced key instances from adventure instances
oh I see.
Hmmm wait, I am still kind aconfused what's going on between here.
so the ResourceLocation argument only parses the input string until it hits an invalid char, in that case, the X, and returns the resource location minecraft:e
Yeah
then just after it finishes parsing with no thrown exceptions, it checks if the next char is a space ( ). If it isn't, it throws that error underlining the bad input
look on Line 371 of CommandDispatcher, just after it parses with no runtime exeptions
it peeks to see if the next char is space, if not, throws the dispatcherExpectedArgumentSeparator built in exception
well it detects the X and, trips that exception which is then printed in the error message
the parsing logic expects the next char after finishing a parse to be a space, if not, it creates that exception
and ResourceLocation#read(StringReader) only reads on the reader until it hits an invalid char, then it returns what it already collected
@tacit umbra Ohh I understand.
The issue is doing validation logic in the argument, which takews precedent?
correct. it's weird that the resource location doesn't just read until a space, if it finds an invalid char, throw an exception
Yeah okay, I see.
So yeah in general I think that's fine then, lol. Vanilla arguments are gonna be quirky, I was just super confused.
Yeah alot of arguments do stuff like that, especially the string arg with like = and what not.
Agreed, that should be reworked.
Whether a new type, idk.
But that's defo yucky
if you add a Coordinates equivalent, you can do like 5 argument types with it
Vec2, Vec3, ColumnPos, Rotation, and BlockPos
Yeah okay, we should do that then.
a bunch of those are missing dedicated types, but it's not required really
I think it's good to at least have a generic type for future proofing
Are there any other notable argument types we are missing?
we can probably do the ranges using guava's Range type, for int and double range. It'll use the box types instead of primitives, but I think that is fine
the scoreboard stuff is interesting, cause afaik the suggestions will be based on the player's current scoreboard right? I don't think the server is queried for that
I mean, that makes sense given the entire scoreboard is sent to the client
don't think that any of the built in suggestions ask the server? 🤷♂️
that's not true at all. it queries the server for a bunch of stuff.
sounds, I think it does query for scoreboard objectives actually looking at vanilla src
I always think this is interesting
well those are just a few of them, any "custom" suggestions on a node use the server for suggestions
Yeah
if a node uses the argument type's default listSuggestions, then it sometimes doesn't ask the server, but look at ObjectiveArgument#listSuggestions
Oh that's interesting
that second "if" block is triggered on the client, and that queries the server. SharedSuggestProvider#customSuggestions is overriden by ClientSuggestionsProvider to send a packet to the server to query
hm
That seems to be the only argument that does that
lol wat. it was just the first one I looked at. hadn't yet looked at other scoreboard stuff
see, afaik most of the stuff relating to the scoreboard is sent to the client
Oh wait no, that is used in alot of places
so, idk what all they do there, would be odd if they queried the server for all of it
they don't for some stuff too. Like EntityArgument, that is usually done on the client. Paper forces it to the server to fix a bug
but in vanilla, that doesn't query the server
So in some cases they handle it client side only, while in some cases they split it? Like see GameProfileArgument#listSuggestions
Wait, what, no. That would occur both on server/client right?
yeah it would, but it's not gonna run on the server. A couple uses of the game profile argument have custom suggestions set too, the op and deop commands use server suggestions to get the list of opped or not opped players
But what makes that not run on the server? CommandSourceStack is Shared too
because the client isn't gonna query the server for suggestions
when the client is parsing the command input, its gonna get suggestions for that node, not query the server cause ASK_SERVER wasn't set unless there's a custom suggest on the node
Yep yep okay
the ASK_SERVER is set when its creating the root node to send to the client to replace any custom suggestinos on the node
otherwise it'll just use the listSuggestions method built in to the argument type
But ObjectiveArgument is weird becauase it calls the customSuggestion, right? Which does the server hop
but sometimes even that method queries the server, like ObjectiveArgument
Yeah so that seems that objective argument is the only argument like that then.
Nothing calls customSuggestion like that
well, that's not the only place that customSuggestions method is called on the client
Wowwy, okay so I didn't know that logic got that in depth in some cases.
Ask server, objective argument, and resource key arguments
I do not know how that would happen
that orElseGet bit
if you send an argument for a registry that doesn't exist on the client?
If it's an invalid registry?
they all should exist
Yeah that's weird lol
custom registry support? lol. API to create custom registries
actually... I think some of them "don't" exist
Ok, so the composite RegistryAccess.Frozen the client uses has all the built ins, and all the remote ones sent in the login packet
Ahh, do you mean like worldgen registries?
but that isn't all of them
yeah, some of the non built in registries still aren't sent to the client
I was thinking that all non built in registries were sent the client, but that's not true
a registry registry???
I guess it makes sense tho
yeah, so only these are sent to the client, all the other non built-ins aren't even on the client
I mean...
let's gooo
yo bro
now make it sync
where do I see the non built ins
Is it just Registries
Ahh okay
they are still called "worldgen", but they really aren't cause like chat type and armor trim stuff is there too
Mmm yes, the worldgen/multi_noise_biome_source_parameter_list registry
yeah, if I thought about where the resource key arg would be used, this would be obvious. can place custom structures with a command
structures aren't sent to client
so it had to query the server
Mhm
back to scoreboard arg types, so it looks like we can add Objective. It would be interesting if we modified the vanilla arg slightly to accept any scoreboard, not just the main one
so you could create an objective argument for a custom scoreboard...
Scoreboard api 😟
could do operation argument, its not too crazy
could do angle, just making it an ArgumentResolver<Float> essentially
I think those range arguments would be nice, the client side completion is nice for those.
Maybe TimeArgument too
no clue what the swizzle argument is
is swizzle a technical term? its used in the execute command, which like 95% of its functionality is foreign to me
nah, don't think its a good idea anymore. The TeamArgument seems to only rely on the client's known team names rather than ask the server
oh that is annoying tho... cause it breaks the commands for any player that might have a custom scoreboard set
entity anchor.. don't you have that for the teleport api stuff?
Ermm, yes.
Sounds like a dance move
oh ew gross. we can't cause they have the same erased class, Range.class
well we could make helpers to get it.. ugh generics suck with brig, why didn't you just use type tokens MOJANG
also, there aren't any completions for it. the completions you are thinking of are in the selectors
but it works
I mean syntax checking
yeah, that works
will /execute be able to run plugin commands with these changes?
Yeah, I believe so
Or at least it used to o.O, maybe something changed as it doesn't seem to say that in the PR description
It does
And command blocks, from my testing :)
I'm back from my holiday, I'll do some testing later
whenever this needs to be documented, mentioning that all commands now work with /execute and command blocks will be quite important i think
using execute as @e run command might run the same command many times very quickly etc
including existing non-commandsourcestack commands that just use get sender (where it would run over and over)
Is there any ETA for the merging of this PR?
no
I can't guess
We generally don't offer ETAs on stuff
idk if it's mergable right this second or not
and personaly, I'm kinda snookered
Yeah no I completely understand, I'm not asking you for a deadline or something. Just interested really
How long does a PR of this size generally take you'd say?
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.
Oh and I just wanted to say that this api feedback channel is an amazing idea, talking in #paper-dev about Paper's own api (as the channel description actually suggests you do) would have been very annoying
I think the issue is still present
May I also suggest allowing LiteralArgumentBuilders as inputs to register? Vanilla also has it like this
It will let you omit that build call at the end of the command, which is kinda nice
I can't replicate it the same way
when I have the permission for the sub_command, it shows in suggestions
when I set it to false via luckperms, it goes away
Could you try my exact command
This one
It should definitely not show sub_command
you mean check the sender name?
doesn't show any suggestion for me
if I invert the requires check, it shows as my username isn't xpple
This is my exact code java this.getServer().getPluginManager().registerEvents(new Listener() { @EventHandler public void onLoad(ServerResourcesLoadEvent event) { event.getCommands().register(TestPlugin.this, Commands.literal("root_command") .then(Commands.literal("sub_command") .requires(source -> source.getSender().getName().equals("xpple")) .executes(ctx -> { ctx.getSource().getSender().sendMessage("You are xpple!"); return Command.SINGLE_SUCCESS; })).build()); } }, this);
and what do you want me to do to replicate the issue?
And it shows
is your username xpple?
But then says
No
ok, well mine isn't either, and I do not get a suggestion
make sure you are up to date
Idk, I just really wonder why it's showing for me
I have VanillaArgumentTypes.doubleRange() available, that confirms it
make sure the server is up to date I guess, not just what shows in your IDE
Oh fuck me
Lmao sorry
I forgot I had to manually update the jar for my testing server
Yeah that will undoubtedly solve the issue
Yep, solved
Sorry for the inconvenience and thanks for the fix :)
ok and yeah, right now plugin commands don't seem to override vanilla ones, that will be fixed
ok, that's fixed.
we have to determine what the best way to deal with argument types that have generics
brig's CommandContext doesn't support any type token, just Class which is only used for the generic to cast, and to check if the parsed argument value is an instance of that class
no vanilla argument has a generic, but we use a generic for several arguments that require the context to resolve the final value
Should we just make concrete classes for each of those? it'd be like 6 of them
SingleEnttity
MultipleEntities
SinglePlayer
MultiplePlayers
GameProfiles
BlockPosition
or we have some helper method to get the parsed value from the context like currently exists on CommandSourceStack (getResolvedArgument)
Registry related arguments do
yeah, but they don't do any unchecked casts, well not directly. you have to do an unchecked cast somewhere
Why? What's wrong with casting? Add get<Argument> methods in the argument class and suppress the unchecked cast
in what argument class
VanillaArgumentTypes
yeah, that's a possiblility like I said here
It's normal in vanilla to have get<Argument> methods anyway
can get away with 1 cause those arguments can share a parent type, ResolvedArgument
yeah, but those are on the argument type, not clumped all together as static methods on one util class
Yeah that's an unfortunate side-effect of having them all in VanillaArgumentTypes but I don't think it's a problem
But, really, I don't see the point of adding lots of classes
Tbf it kinda makes sense to have the get<Argument> methods since they complement the <argument> methods well
Ok, the TODO list at the top of the PR is I think what there is left to do https://github.com/PaperMC/Paper/pull/8235
at least what I could think of
maybe an offical way of changing the fallback prefix in the new api? cause having a fake plugin instance that just overrides name (and isnt registered at all) works, but seems a bit too hacky?
idk
What fallback prefix?
like if the plugin is named myplugin, then mycommand is registered as /mycommand and /myplugin:mycommand
there are methods on the commandmap to register with a custom fallback prefix, but not in this brig api
it works if you have custom plugin interface that returns something else for getMeta().getName() (or whatever it is), but then there is no longer a correct refference to the registering plugin, which may break others (say a /help thing that gets more info about the plugin from it)
I don't think we want to support that?
the prefix should be the plugin name
that's the whole point of the prefix
even if you want to do it for another plugin?
you pass in that other plugin's instance then
out of curiosity does it mean that https://jd.papermc.io/paper/1.20/org/bukkit/command/CommandMap.html#register(java.lang.String,java.lang.String,org.bukkit.command.Command)
(string fallbackprefix on commandmap) is not intended / smth
declaration: package: org.bukkit.command, interface: CommandMap
that's been exposed for years
but
bearing in mind that upstream never exposed the means to interact with the command map for the past decade
it's basically quasi internal stuff
is this a bad idea then lol
https://gist.github.com/the456gamer/e8bb96cc7aedc0b6c93d9fed25b60f5a
yes, that is not supported API
PluginMeta is marked as non extendable
still don't know why you want a custom fallback prefix
I kinda understand, the plugin's name may not always be suitable/preferable for the prefix. I personally dislike the fact it's capitalised for example. Namespaces are generally lowercase
But ig the fallback prefix is not actually a namespace technically
wait can you have 2 plugins differing in only case loaded?
or are ids compared case insensitive and its just for display
we could then add a separate field in paper-plugin.yml for setting the command prefix
but I do not think it should be dynamically set
funni unsupported "api" go brrrr
Yeah no I agree
it's literally just there to provide a stable name for people to deal with
Tbcf, this would be nice, but imo nicer - and definitely more controversial - would be adding an id entry which could potentially be used for other stuff as well. This way you distinguish between something that should really only be visual (the name), and something that should be used in code (the id). But this is a hot take, I think a prefix entry is fine
More of a Bukkit thing I suppose
so if i have to migrate from old to new, should the prefix on old backwards compatable commands change to match the new plugin name (say it merged/ split)?
i know this is all hyperthetical
How do the custom argument types work behind the scenes? Are they just remapped to their parent type when sent to the client?
Cause like, how would that work with custom overridden parse methods (the converted ones are obvious)
basically they always parse as valid client side iirc (assuming your validation is stricter)
like i tried to do a literal thing, and i only got the red text while completing when it wasnt a valid string (mismatched quotes iirc), even if it doesnt parse, and running the command gives an error
the parsing is done on the server. on the client, the parsing is whatever the native/primitive type parsing is
Yeah that's what I expected but that feels very wrong
at the end of the day it is kinda wrong
Non red text giving command errors
but, it's a common feature used by command frameworks
Doesn't sound intuitive
Well, it's not, but such is the limitations
I mean there's no way for the text to be not red without a client mod
ideally mojang would let the server give some feedback
also, that's how its been forever pretty much
if you want the real types with the real parsers to exist on the client as well, they need to exist on the client as well, as well as the network registrations etc
I know
you can only do so much from the server
brig limitations :(
But like
Unrelated to brig
its not a brig limitation, its a "only modifying the server" limitation
not new, and not exclusive to "bukkit"
The converted ones at least give you a little bit more hope non red text will be parsed correctly, but with custom parse methods that safety is completely gone
What is the reason for custom parse methods anyway
what is the difference where you throw the error?
Because it's a common part of command frameworks essentially
can just throw it in the execution, there was no red text there
I'm trying to say, what is the point of sending the client some argument type that you promise the client is what you'll be using, only to use possibly completely different parsing logic? Basically in what situation is a custom parse method better than a convert method
I'm aware that the convert method may fail the same way
the entire thing is that the brig systems strengh is that it maps types during parsing
take Location
How do you define a location, how many args does it take?
Now, you could have "world x y z", or, "x y z", both of those generally being parsable based on the current context
if i wanted to make a fancy location parser, then
3 or 4 or maybe 1 (here)
(but 1 "arg")
ofc, the way the client will treat that will kinda suck, but, that needs to be boiled down into a parsable type
otherwise you just go back to the old classic of treating everything as a giant ass long string, and then you lose the advantage of brig in general
ofc, we are operating within the bounds of limitations, the client doesn't understand this stuff, so for a location you'd just try to conform to the types that vanilla understands where viable
but, variable length stuff is a key area where being able to override the parse method to have some control over the args is key
in fact thats what vanilla did for clone, right? they introduced an optional "from <world>" thing instead of a location with a world as 1, right?
like using the literal as a marker
So what native argument type would you use for this?
Location is a great example. I want them to enter a location that is above them. Block pos argument is great, but it won’t show “red text” for positions below. If I use the custom parse, and can set the string reader pos to exactly the error which then shows a more helpful error message than some generic one
If I just used the converted one, I couldn’t show as specific an error
Well, for a native type you'd sadly need to make it a greedy string, given the lack of shared understanding
I could still throw an error, but it wouldn’t have the string reader in the correct pos
it's just an ez example though if you don't wanna bake it into multiple seperate args
Native meaning present in vanilla
as said, greedy
it's a nice util feature
It would be useful, cause you have a reader, and can use the brig exceptions
it's not perfect, but it's a common thing that commands want to be able to do
You can’t do that in “convert” cause it’s already parsed
Wait I think I know of a different use case
Suppose you want a block argument type. You use block predicate as parent argument type and override the parse method cause you don't want a predicate. That way you have a perfect block argument type that is 100% consistent with the client
:einstein:
Perhaps add this as an example I think it illustrates the power of a custom parse method very well
Where are the custom argument types remapped internally?
What do we do with arguments that require command build context?
can I get an example
Block predicate
Ideally the command build context is supplied in the event or something?
So I guess we'd need a separate event for commands
Idk if that's applicable here, sorry if it's not
@proud timber I don't think there is a point right? At least not yet. The vanilla args are constructed behind the scenes so you don't need it to create any of the arguments in VanillaArgumentTypes
Yeah not yet, but what if we want to expose the block predicate argument as well for example?
Or registry related ones
it would just use it behind the scenes to create it
why would the event expose it only for you to use it? why not just make the method VanillaArgumentTypes#blockPredicate use it in its impl
Is that possible? Where do you get the instance of it from
yeah, its held in a field in ReloadableServerResources
either way, if its needed, we can add it later. THe event is changing already, its just not in there yet. the command regsitration event is probably gonna move over to a lifecycle event, the system for which can be found here
Is that just accessible?
If so, what is the point of passing it around everywhere as happens in vanilla
I mean that's how you use it? it uses that field when it creates nms.Commands
it doesn't have a getter, and its a private field. the ReloadableServerResources is re-created during a /minecraft:reload and a new one is created
I'm saying how do you get that field without having an instance of ReloadableServerResources
I should probably have a look at the code
you can get the instance from MinecraftServer, there's a field for it there
And how do you get an instance of minecraft server lol
MinecraftServer#getServer a static method
not in vanilla
Ah that explains it
Fair enough
Man that should exist in vanilla btw
Would make life much much easier
But anyway yeah that solves it
also, the suggestions thing you asked for on the PR... my one reservation is that they are opinionated. We aren't trying to create a command framework with any opinions, just expose brig as directly as possible
Yeah that's true, I should keep that in mind better
It's just that when I think Brigadier
My mind goes to custom argument types and everything
For which these helper methods would be very useful
and you can create them yourself, exactly as you want them
like the string matching in SharedSuggestionsProvider special cases _, checking if your string matches either the beginning or any text after each _.
that is an "opinion", and I don't really think it belongs
side note: @neat radish should we make CommandSourceStack implement ForwardingAudience?
vanilla's CommandSourceStack has "sending messages" methods
sure
Yeah I have, but I fear that everyone will copy over all those methods, which is a bit annoying to do. I agree that that _ thing is a bit random, so what about just the one that suggests an iterable of matching strings?
Also yeah I also think this would be nice, currently I just do source.getSender().sendMessage()
Does that interface also have something to broadcast to ops?
That could replace source.getSender().getServer().broadcast(component, Server.BROADCAST_CHANNEL_ADMINISTRATIVE);?
That’s be a separate method, but one to consider adding. Audience is just all the message, action bar, title, etc stuff that CommandSender implements now
Right okay
@tacit umbra it seems the command build context is actually separately created: https://github.com/PaperMC/Paper/blob/5917de41e39ac28d1b207ad4ea70091db0dd034f/patches/server/0989-Brigadier-based-command-API.patch#L849
Might have to change that, can’t look now but it’s probably missing something.
Yeah
Shall we discuss the todo list some time?
would something like
@NotNull
public org.bukkit.command.CommandSender getTargetBukkitSender() {
if (this.entity == null) { return getBukkitSender(); }
return this.entity.getBukkitSender(this);
}
in CommandSourceStack.java be useful?
Without understanding too much about this, that sounds like a bad idea. If adding context is something people need, we should have API for adding context
i had the idea to implement custom settings for commands using a custom css, with a command like execute to modify context from the default
(like
plugincommand with-setting <key>=<value> and output.verbosity=verbose and output.colours=minimal run debug or smth)
Overriding shit in the API always becomes a hassle because new stuff can't be added as easily
yeah i get that
Could this get some attention? Let's just go through the todo list
And could we discuss publicly hosting builds of PRs with the label build-pr-jar on some maven server?
build-pr-jar doesn't publish to maven for various dozens of reasons, managing that would just be ass
Why?
Because we have no mechanism of uniqifiying the IDs?
given how rarely stuff like us actually needing to publish an artifact for, we have no mechanism for it
Could it be possible to add pr number to the artifact I'd published with paperweight to the ci?
We have no sane way of doing that atm
Yeah I have no idea what I takes for it to be secure
publishing transient builds to the maven server is a pita because removing them generally becomes a headache
not to mention the headaches over this being such an infrequent requirement makes it somewhat of a non-ideal arrangement
a solution would be nice, ofc, but I don;t think shoving unstable builds into our maven repo is really a good call
You don't have to remove them though?
It's definitely doable
It's more the "we don't want to persist them for forever"
It's doable
it's just an entire bunch of headaches over how we wanna figure to set this stuff up
it's on the list of stuff we want
it's just we need to figure out a way to do it which doesn't compromise the main repo
and then setup a way to be able to inject pr info into the thing which is a headache on gradle
It's really not worth the effort generally
and then we also need to setup a policy for it so people don't expect that we care to keep those builds around, etc, etc, etc
The build PR Label was created so that issue reporters could validate the fix
It serves a need for us a maintainers
maybe when we start publishing a dozen bunch of PRs like this which require more plugin dev effort, it will make sense for us to drop everything to start drafting such a set of policies and creating a repo for it, etc
I mean, even that becomes an entire set of issues
there is no real way to do this securely without basically rolling our own magical maven repo stack eqsue thing
Maybe we can copy the approach of some other repos that have done this
idk any other repo which has been stupid enough to setup such a mechansim
most people would just setup CI for the branch and remember to publish it under a different version, etc
Just jitpack it
runs
I mean, having a service that emulates a maven API and builds PRs on demand could be a fun project
Wouldn't actually publish anywhere, just cache
that was one of many thoughts I had
could just run publishToMavenLocal and then setup that as a maven repo tree
I feel like we just accidently gave mini a distraction from hangar
Problems with that approach?
that only works for branches owned by us
and requires a bunch of leg work to setup a maven repo
setup the CI system to build it
Why?
Setting up a maven repo isn't all that difficult
Because we do not have the ability to setup teamcity for every single repo people desire a build for
It's not difficult, it's just a bunch of work
- TC only gives us so many build configurations that we can have, not to mention the security implications of running 3rd party builds within our ecosystem
- Gradle does not offer a convenient way in which to override information in the build output in a reasonably secure manner that gradle does, i.e. the version information, etc
- We would need to figure out a reliable manner of hosting temp repositories in order to manage this mess, including figuring out a reasonable policy in which we're not expect to care about hosting such builds for the next 200 years
This is what I have in mind, which is probably a naive oversimplification:
- Have a separate maven repo (something like https://repo.papermc.io/repository/maven-snapshots/)
- If PR has
build-pr-jar, then execute snapshot publish script defined inbuild.gradle - The script would redefine the build version to be the commit hash
- The script builds the PR and publishes
We don't wanna spam our repo with builds like that
Only the Paper team decides what PR gets build-pr-jar though
gradle offers no sane mechanism to define a build version override
Heck, create a new label for publishing
We also cannot/will not run that stuff within our own production build setup
It does? I think you can just redefine the version in the publishing block no?
modifying the version info in a script just sounds like a fragile insecure mess
There is no flag to do it, we'd need to modify the actual build script
in which we introduce an entire set of headaches over security
Wym?
I'm by no means a Gradle expert but you can just do version = ...
how?
How do you define that version in a build in which you do not control the config for?
We would need to expose environment variables or something for it
but, then you introduce a bunch of risks over the fact that people can set that stuff in the build config
it's an entire set of headaches which we'd need a proper isolationary solution for, as was already proposed
publishing {
publications {
mavenJava(MavenPublication) {
version = ...
// ...
missing my point
maven offers a flag for you to do that
We have literally 0 mechanism of injecting overriding version information in a manner which doesn't pose a huge obvious gaping security risk
iirc you can set the CI pipeline to only run if certain files were not modified...
otherwise only with manual approval
so you put all buildscripts in the no-go filter
No idea if TC supports that, but its' 100% not something I wanna contend with
We have an idea of how we can maybe wrangle something together
it's not the full picture, however
So I've been messing around with this idea
https://github.com/the456gamer/paper-build-pr
I'm not 100% sure if it's secure ATM, but it publishes to GitHub packages
Specifically, I publish the dev bundle under the group
io.github.the456gamer.paper-build-pr.<pr number>.paper
Where pr number is a pr with the build jar label
No, it's obviously not secure
Actually nvm I've just realised I'm publishing paper-server somehow, let me take it all down
Oops
relying on sed in order to "safely" replace information in a build file is deeply flawed and is exploitable by a child
The only way I could ever see this working is to basically publish to maven local and then host that
Ok the repo should be private now
Does it change anything that it only touches "build-pr-jar"?
I guess that's a lot of trust on paper, but would raise the barrier of an actual attack
Either way, for me it was a cool poc
Btw how does paper publish to maven so that paper-server isn't included? I'm guessing it's not publishAll... as that's what I used
Is it done by publishing the Dev bundle separately to API /mojang API?
we just use the publish task
some property thingy too to get it to publish the dev bundle
yeah i saw the property to publish with dev bundle.
is changing the group for within the dev bundle not needed? that would remove one of the "sed"s, and i wasnt 100% sure abount how paperweight treats it
instead of seding to modify within, is appending at the end any better?
huh publish seems to publish paper-server as well. does it get filtered repo-side for you, or do you publish sub project separately
I wanna say that we just publish the subprojects or something, I don't remember 100% and too dizzy to care to peek
ok ive made the repo public again now that its not going to get me in trouble with microsoft
https://github.com/the456gamer?tab=packages&repo_name=paper-build-pr
it published (havent actually tested using it yet, but oh well)
it still feels like im giving any pr's i build rce, since i am. its just how gradle works as a build tool. as far as i know, the most it can do is delete the other packages in the same repo, ruining it for everyone (or maybe replacing all packages with a malicious version :/)
Which is why the only safe approach ever is pretty much going to be ephimural repositories
yeah.
im giving up on this now, ill leave it as-is incase @proud timber wants to try using it for this pr
notes on github packages: you need to authenticate with the github repo using a PAT to build the project, https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-gradle-registry#using-a-published-package
but it wont auto-build any new versions
Woah that's cool
im suprised the dynamic matrix builds worked tbh
and that it lets me run all 16 at once
apparently its limited up to 256 per matrix
Does the PR need updating for 1.20.2?
Tbh, this will be sitting around for a bit longer until it gets more attention. Just how things work here.
People are busy 🙂
tbh
I really like the velocity bridgiar api
idk if thats default or what but its really nice
it has some slight improvements over standard brigadier but is still quite similar
velocity takes over the entire dispatcher, and so it's able to do things like replacing stuff and providing more raw access, vs paper which needs tl deal with the impl vs api seperation
This PR is blocked by the lifecycle api PR, if you would like to look at it. 🙂
Sad
Niceee
Brig API updated a bit
Cool
@neat radish found another structural issue with the server-side of the command registration stuff. It is designed to only exist when MinecraftServer exists. The ApiMirrorRootNode gets the dispatcher from MinecraftServer which doesnt exist when the bootstrap side of the event is gonna be fired.
That event is probably gonna be fired in ReloadableServerResources#loadResources
Hmm okay, thanks for info. Can fix
What's the state of this PR currently?
And where can I find the implementation of the VanillaArgumentProvider?
^
Yeah but there have been some recent commits
Also
Wth why couldn't I find that
Ah I probably didn't expand the git diff
Anyway this maybe needs to be looked at: https://github.com/PaperMC/Paper/pull/8235/files#diff-0374be20030ef6f97e956d68c28e64b332f778d22715c6f3bc4815163f0b3948R874
A new CommandBuildContext is still being created
It should probably use the existing command build context
Thanks, btw
what am i looking at
this?
Yes
don't see the issue
I don't think you're supposed to create a new instance of it
Might cause sync issues?
I think you can get it through ReloadableServerResources
why? it doesn't hold any state
the problem is using the VanillaRegistries, not the creating a new instance of it
I actually think I've mentioned this issue before?
Kinda
But okay then that should be fixed
my god, please add this
don't commands registered using the commandexecutor convert to brigadier too?
Those commands are registered into the bukkit command map which is then basically copied over to the brigadier one
May I request a status report?
No, you aren't the manager, lol
hi, i'd like to speak to the manager please
Errr, may I speak to a public representative
I understand
Just wanted to know the status
But cool :)
That is the lifecycle event system I suppose?
yes
Is there anything we (I.e. random users lol) can do to help with this PR/getting it merged sooner? assuming it's just testing, is there a specific part that testing would be useful for (e.g. testing compatibility with current command systems vs testing the new API)? or just generally try stuff out and see if they work as expected?
I tested the new API and found a few bugs, so I think the API could use some more testing
I don't see any comments on the PR about that
Because I reported them here
That was two months ago
Yes?
I see some of them were dismissed as not actually a problem, have you checked whether any of them are still a problem?
This is why using Discord for bug reports sucks, no one has any idea what the current status is 😛
They were all fixed
Iirc
If they were, it was probably mentioned here that they were
These were fixed I think
oh jeez that was even further back
So yeah, those should have been comments on github
@ancient wolf @proud timber The best thing you can do is test this with existing setups. Make sure all bukkit commands work the same
The actual brig API is going to be marked as experimental for a while, right? So if some of the details for it are wrong that's not too big of a deal. That means the main thing would be to ensure existing non-experimental API still works
Yeah, legit just plop the jar in your server and if there are any changes they should be reported.
Though the issues I pointed out definitely weren't all details
Last updates have been done
Please test the server jar located at https://github.com/PaperMC/Paper/pull/8235
Try seeing if pre-existing commands work fine as behavior.
Wanted to let you know that when switching to use brigadier, it works perfectly until you reload. When using the .suggest() method in the command, it doesn't work after a reload and requires a restart to fix.
My code:
https://github.com/Dueris/GenesisMC/tree/origin/src/main/java/me/dueris/genesismc/command
Wdym "it doesn't work"?
Custom auto completion doesn't work. The command itself still works tho
Oh, interesting...
What command exactly in this case?
Why are you reloading? Consider reading: https://madelinemiller.dev/blog/problem-with-reload/
On a different note, is this system even supposed to support reloading?
Sry for the late reply, was getting pizza in the oven lol
No stress
All 3 in the dir
Bukkit reload
Could you potentially double check that ur properly updating those fields?
There's a chance that it is maybe referring to an old instance of your plugin or something...
Maybe try replacing those with a static list to test if this is a conversion issue.
Look on line 83, it's a ResourceLocation argument that pulls from the registry inside the plugin that suggests each "tag" to the suggestion builder
Upon reloading it doesn't suggest those tags anymore
Everything in the cmd still works tho after reloading, except for the suggestion.
Try replacing that with a dummy list. Because what I am saying is there is a potential that reloading causes CraftApoli.getOrigins(). to refer to an old instance
Of OriginCommand(sry for not specifying lol)
Like for testing, make it builder.suggest("example") or somethin
Why would it refer to the old instance? It shouldnt tho, it always updates correctly when reloading the plugin. But on disable I do clear that registry to ensure no overriding or duplicates in the registry. I can do a normal suggestion like that, gimme ~20 minutes tho, I'm away from my computer
Now that I think abt it, that does make a lot of sense.
That's kinda the ugly nature of reload
I can, again, really recommend this article: https://madelinemiller.dev/blog/problem-with-reload/
Points out the problem with that command and the concept quite well in my opinion.
During reloading I could "update" the map by splitting the command suggestions and the origin registry and during disable, clear them both, and on enable I could update the one for the cmds(making the brigadier cmds point to the cmd suggestions map)
It is a very good article, ty
im on my pc now
working on testing rn @neat radish
@neat radish it does seem to break on reloads
before reloading
after reloading
"sdf" was a suggestion i gave teh builder through "builder.suggest()"
after reloading, it didnt display
https://github.com/Dueris/GenesisMC/commit/885735d9ad2374493a0c6a670789b18dba43617f
I also made this commit, making "clones" of the registries within the plugin
Hmm okay let me test
do u want a build of my plugin?
nah I should be good, will test with a local command
what's your favorite species of icecream?
lol
will try this tomorrow, try and make my plugin commands look cool there lol
Yes
The check for if they were null was to see if it was bc the cmd was overriding the previous one during reloads. It always returns true tho
Bc it's not in the cmd map
It was a theory tho lol
@solemn ferry So the thing is what you are doing isn't exactly supported
how so?
Ur using NMS to directly insert commands into the dispatcher
yeah? I thought that was how it worked lol
im assuming I did something terribly wrong
yes but, it's a little different using my API
Ah, i see
i thought brigadier had already been inside paper, since the brigadier-related classes were in there(unless im totally wrong rn which i probably am)
But the big thing here it seems is that current api doesn't support reloading.
@tacit umbra Do we want to fire these lifecycle events on bukkit reload
No you aren't
So how would I change it to use your api lol
it should already I thought
it fire during minecraft reload
and bukkit reload fires that
doesn't seem so
which is why I am confused
Does reloading clear lifecycle events?
Maybe this has to do something with the ordering of things?
it does clear them, but onEnable is called again, so it should re-register them
But is onEnable called before the life cycle events get called
(in reload)
Because at least the commands aren't showing up and there isn't anything running it seems
oh its possible we need to move the firing of the JavaPlugin lifecycle event, yeah. Its fired at the end of the minecraft:reload sequence. But if that happens while plugins are unloaded...
If you potentially have time to look into that I would greatly appreciate
@neat radish how would I go abt changing my current system to work with your api?
That's alright
Ty for ur help
I'm adding an issue report inside my repo to remind me to update to ur api when it releases
Ok, I pushed a fix for the bukkit:reload command issue
keep in mind, that if you register commands inside the plugin bootstrap, any bukkit reload will throw an exception and not reload anything
bukkit:reload requires unloading all plugins. The pluginbootstrap is not called again when the plugin is loaded back up. So any event handler you register there will just be erased and not fired again.
the benefit of registering commands in PluginBootstrap vs JavaPlugin is that commands registered via bootstrap are accessible in datapack functions
but that's pretty much the only difference, so if for some reason you still want to use bukkit:reload, registering your event handler in JavaPlugin#onEnable will be fine
Alrighty. Ty for ur help!
One last question, would moving the command registration(the nms way that I currently have) to the plugin bootstrap fix this issue? If not that's fine, I understand it isn't rly supported XD
Oh
Mb XD
I got confused on what you meant for a sec
My apologies
Ty for your help
I was wondering if this conversation (#paper-contrib message) was related to my comment on the PR (https://github.com/PaperMC/Paper/pull/8235#issuecomment-1826166587).
I think one option you can employ to fix the CME is a ReentrantReadWriteLock. I found out about this when trying to fix the CME myself for a Brigadier-based command API (see usage in my code here).
We don’t have full control over write contexts to rhe thing, and so afaik using a lock is not really an option
Ah, writes don't always happen via API calls?
Indeed
I suppose the lock could be accessible (or at least interactable) publically. API stuff would be controlled to avoid CMEs, and if anyone wants to do their own read/write outside of the API it'd be their responsibility to use the lock properly.
Is ServerResourcesLoadEvent still the correct event to listen to? It seems to not be triggered
oh i think I found it
why do you force push the branch instead of just adding more commits?
Because that’s how paper stuff works easier
i dont understand... isnt the end result the same if you sqush it
im just asking because i'm trying to maintain a kind-of downstream of this PR
with my own publishing stuff ontop so that I can develop with it
and its a bit more annoying to have to force push all the time
and cherry-pick my patches
@river flame Well again, you aren't really meant to do something like that... it is pretty standard to force push like this, so I am sorry it's not working well with your setup here.
What I really would instead encourage is using a standard paper fork, but then just downloading the patch that is on the PR and importing it yourself. (As most of the changes are isolated to two patches)
And then whenever you feel like it you can redownload my patch to update.
im publishing it to a sonatype nexus instance so i'm not constantly publishing to maven local on my dev machines
also so that the CI pipeline with my plugins doesn't fail
But I do appreciate your testing here, and I am hoping that we are near the end here.
i hope so too, im rly excited for this api lol
same, just got my code working on the new version
everything seems to be golden
sharing brigadier command trees between velocity & paper :)
I just tested the jar on a copy of our production server, and every existing command seems to work perfectly. Even my somewhat unintended way of manually registering some commands to the command map still works. (Which i didn't expect, but wouldn't care since i will replace it with this api anyway). So in our use case it is a drop in replacement with everything still working as expected. Great work, looking forward to using this API 👍🏻✌🏻
that is very valuable, maintaining existing commands exactly how they are is important, especially with all the variety of things people do around commands 😛
@neat radish Why do brigadier cmds in ur new api get registered via the VanillaCommandWrapper and not another wrapper or a modified bukkit one?
What does this question mean? Yeah I didn't really know what this was asking
In the PR, it says in the description that it uses the VanillaCommandWrapper for registration of brigadier commands.
"Deprecates CommandMap, moving all logic to a brig-backed map for legacy support. (All custom brig commands are wrapped in a vanilla command wrapper)"
I was curious why it does it in the Vanilla cmd wrapper
it's a vanilla BUKKIT command wrapper
so u can interact with brig commands with bukkit Commands
ik what it is, but i was curious why it used that wrapper and not the bukkit wrapper like the rest
Not sure
Prolly just cause I wanted to use a new one
alrighty
since your using the vanilla cmd wrapper then, would it be possible to make it so that u can tell the difference between vanilla and bukkit/plugin cmds?
I mean none of that is exposed through the bukkit command api
previously, vanilla cmds would be wrapped in the vanilla cmd wrapper. I was working on a fork when i was testing cmd wrappers and found that out. now that brigadier cmds are being registered via the VCW, i was curious if htere was another way to detect it
give me brigadier 🙏
When this pull request is merged, in less than 10 minutes I will remove support for all my plugins to versions older than the latest and use the new command registration structure 👀
4 minutes left?
I think they meant it would take 10 minutes from merged to dropping support in their plugins, not 10 minutes to merge
exactly 😅
oh
the english language can be very confusing
even as someone who has only ever known english
"when this pull request is merged, in less than 10 minutes ..." vs "when this pull request is merged in less than 10 minutes, ..."
Okay I'm bored so I'll go through the pain of building it locally again and testing it in my mod
Amazing I was able to build it in just over half an hour
Everything seems to work!
One question though 🤔
Should a player without access to a command be able to see the help info?
generally, no
Then either I did something wrong or that needs to be fixed
Also I really like the new way of registering commands
So much cleaner
- this.getServer().getPluginManager().registerEvents(new Listener() {
- @EventHandler
- public void load(ServerResourcesLoadEvent event) {
- event.getCommands().register(BetterConfig.this, ConfigCommand.build());
- }
- }, this);
+ this.getLifecycleManager().registerEventHandler(LifecycleEvents.COMMANDS, event -> event.registrar().register(ConfigCommand.build()));
General question: Is this system supposed to register namespaces that contain uppercase letters? Seems unnatural to me since every other namespace in Minecraft can't contain uppercase letters if I remember correctly.
That is being worked on
I mentioned this issue as well
Oh, good 👍
Although Owen seems to have removed the to do list
TODO
- [ ] Should LiteralArgumentBuilder be accepted in register methods?
- [ ] Best way to handle argument types with generics? Should we have static getXXX methods on
VanillaArgumentTypesfor all types?- [ ] Handle nullability of "resolved" arguments as it may not be consistent across all of them
- [ ] Block registration via Commands outside of the event context (will be handled by lifecycle event system)
- [ ] Move events we want from papermojang-api
- [x] Make "primitive" vs "native" consistent across the API. Primitive I think doesn't convey that we usually mean all argument types native to minecraft
- [ ] https://github.com/PaperMC/Paper/pull/9629
- [ ]
command-namespaceoption forpaper-plugin.ymlto configure your plugin's default namespace for commands
Last option would allow it to be lower case
But technically commands aren't namespaced
No, I meant rather to take the plugin name as namespace (which is fine) but since that can contain uppercase letters, register the plugin name with a toLowerCase() call
So no namespace is uppercase
I know. That is just Bukkit's way of avoiding conflicts
command names should be lowercased
so, if that actually did register a bad command that would be a bug
Paper lacks a proper plugin id, the name kinda functions as one
thouh, they're not like, real namespaces, as already said
though, upper case afaik is fine
or, well, actually, I think that there is a weir bunch of coercion logic around in registering stuff
Obviously, I know that. Bukkit has done it the same way.
That's what I suggested initially but it ended up as an entirely configurable prefix on the todo list
But @neat radish why did you delete the todo list?
Sure, Brigadier accepts that, I just thought it was weird since every other namespace can't have uppercase letters
Definitely
I'd imagine because it's generally considered close to merging
In response to why it was deleted?
But yeah instead of a config, we could indeed also just call toLowerCase for every command
I don't think that breaks anything
@proud timber Will look into /help thing
Where did ArgumentTypes.blockPredicate() go?
Or did it never exist
I thought it did?
I guess I am mistaken
But it would be a crucial addition because it allows for a near perfect BlockArgumentType
A type that is very common I'd say
It is possible to convert between vanilla and bukkit blocks right? Similar to what is being done for BlockState
Oh I suppose it's impossible to convert between predicates of those types
Is that the reason that argument type isn't added?
On a second note
I suppose ArgumentTypes.blockState reflects the BlockStateArgument in vanilla
But those are different things as I just learnt
So how does that work?
What?
BlockData is what mojang calls BlockState right
Shouldn't it be ArgumentTypes.blockData then?
mojang calls it blockState
Yes
I fail to understand why it would make sense to defer the name of the argument type to conform to bukkits misnaming of stuff vs the defacto proper name for the actual arg, assuming that that is using BD on the bukkit side
The name doesn't matter ofc, but the type of the argument is BlockState
Which mismatches with what it is in Spigot, BlockData
Hence the type of the argument type should be changed, no?
Yes, but mojangs side of that arg is not a BlockState
it's a BlockInput, which stores the BlockState and the serialised NBT tag of a TE there
so, that is analogous to bukkits BlockSate
public class BlockStateArgument implements ArgumentType<BlockInput> {
In CustomArgumentType, is there any reason for the usage of ArgumentType.super as opposed to this.nativeVanillaType
public final Collection<String> getExamples() {
return this.nativeVanillaType.getExamples();
}
public <S> CompletableFuture<Suggestions> listSuggestions(CommandContext<S> context, SuggestionsBuilder builder) {
return ArgumentType.super.listSuggestions(context, builder);
}
Also
Would it be possible to expose a method to create a NamespacedKey from a StringReader?
Can do it myself ofc but that's inconvenient
Why a StringReader?
Cause that's what you get in the parse method
Was more wondering as there should already be a native adapter for that?
Was more just wonering the utility vs the built in things as-is
And what do you conclude?
No idea
Yea, I just was wondering why the built in wasn't enough, I generally dislike tossing around API which ends up in weird places and such when theres better options already
Yeah guess you're right
Can't think of a use case on the spot
I mean in cases where you absolutely need the StringReader itself but those are rare
Btw
I tried to implement the custom argument type in Fabric
And all I had to do was set the suggestions provider to the custom provider and set the type back to vanilla
Basically this
Yes
It seems to just work
same as what paper would do if we support that
But your implementation is much more involved
Well, we have an abstraction layer to deal with
I plan to try to review the code soon, was hoping to do it yester-today, but I, er, 👁️
But you can "inject" as well right
That's all I am doing
Like // Paper start ... // Paper end
I've not seen what we do, be we need to provide the frameworking to let people shove in a custom type and get back out something useful
I have, it's quite involved
What do you mean by that
We don't expose the raw tree nd all of it's glory
we need to shove a condom over it because API layer
When you deal with fabric, you don't need that layer, and so just converting types on the assertion that you can parse it back as i doesn't exactly matter what you see is one thing
I, brain, words, AvEisms
Right
Since my WrappedArgumentType is very much like your CustomArgumentType, what would be the best way to credit it?
GPL requires my code to be open source to those who use it, which is satisfied, but how would I give proper credit
Oh I suppose CustomArgumentType is licenced under MIT
Good enough (at the top of the file)?```
/*
- Copyright (c) 2024 Owen1212055
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
*/
I would imagine so
@neat radish what do you say
@proud timber idc about legal stuff lol
But also brig stuff ours is more involved because we are dealing with the server, you can do whatever you want with the client we cannot
So I remove the notice or?
No no this is for server side Fabric
On the client you don't need to bother with converting them at all
Okay well basically that whole thing mimics one argument type on the server and another on the client
Eh just keep it and ur fine
What whole thing
Idk if this is related to the Brig API, but you get some mismatches with the following argument type: ```java
public class MaterialArgumentType extends CustomArgumentType.Converted<Material, BlockState> {
private static final Set<NamespacedKey> MATERIALS = Arrays.stream(Material.values())
.filter(Material::isBlock)
.map(Material::getKey)
.collect(Collectors.toUnmodifiableSet());
private MaterialArgumentType() {
super(ArgumentTypes.blockState());
}
public static MaterialArgumentType material() {
return new MaterialArgumentType();
}
@Override
public @NotNull Material convert(@NotNull BlockState state) {
return state.getType();
}
@Override
public @NotNull <S> CompletableFuture<Suggestions> listSuggestions(@NotNull CommandContext<S> context, @NotNull SuggestionsBuilder builder) {
return SuggestionProviderHelper.suggestNamespacedKeys(MATERIALS, builder);
}
}
All mismatches: minecraft:chiseled_copper, minecraft:chiseled_tuff, minecraft:chiseled_tuff_bricks, minecraft:copper_trapdoor, minecraft:crafter, minecraft:exposed_copper_bulb, minecraft:exposed_copper_door, minecraft:exposed_copper_grate, minecraft:exposed_copper_trapdoor, minecraft:oxidized:copper_bulb, minecraft:oxidized:copper_door, minecraft:oxidized:copper_grate, minecraft:oxidized:copper_trapdoor, minecraft:polished_tuff, minecraft:polished_tuff_slab, minecraft:polished_tuff_stairs, minecraft:polished_tuff_wall, minecraft:trial_spawner, minecraft:tuff_brick_slab, minecraft:tuff_brick_stairs, minecraft:tuff_brick_wall, minecraft:tuff_bricks, minecraft:tuff_slab, minecraft:tuff_stairs, minecraft:tuff_wall, minecraft:waxed_exposed_chiseled_copper, minecraft:waxed_exposed_copper_bulb, minecraft:waxed_exposed_copper_door, minecraft:waxed_exposed_copper_grate, minecraft:waxed_exposed_copper_trapdoor, minecraft:waxed_oxidized_chiseled_copper, minecraft:waxed_oxidized_copper_bulb, minecraft:waxed_oxidized_copper_door, minecraft:waxed_oxidized_copper_grate, minecraft:waxed_oxidized_copper_trapdoor, minecraft:waxed_weathered_chiseled_copper, minecraft:waxed_weathered_copper_bulb, minecraft:waxed_weathered_copper_door, minecraft:waxed_weathered_copper_grate, minecraft:waxed_weathered_copper_trapdoor, minecraft:weathered_chiseled_copper, minecraft:weathered_copper_bulb, minecraft:weathered_copper_door, minecraft:weathered_copper_grate, minecraft:weathered_copper_trapdoor
These are experimental
Experimental as in?
minecraft experimental
you need the 1.21 experimental datapack to enable the 1.21 experimental features
Wait huh
The suggestions are from the Material class
Oh they are in there already
That's annoying
Do I really need to use reflection to get only the ones that aren't experimental
Material#isEnabledByFeature
You have to enable the experimental flags..
Don't have access to the world instance in that argument type
What if I don't want the experimental features though
Then don’t enable the flags? This is a non issue
Experimental flags are universal not per world
Pass null, or something
needs a world due to how mojang implemented the check
it's not even tied to the world internally
Mojang is in this weird area where it looks like some stuff is or could be per world, but then they end up just passing in global state from elsewhere to back it
it's, weird
You do enable the experiments in the create world screen
But for a dedicated server you set them in server.properties
I mean, but that's not a world
that's a save
Mojangs terminology here sucks ass
Doesn't help that the way CB handles worlds is the code I've been exposed to and is hell
Can't Paper make an API that takes the server instance instead of the world
Yes
But, yes, such a thing could be added
it taking a world is kinda dumb, then again, mojang could wake up tomorrow and limit stuff per dimension
Yeah right
But for now it means you can't really make the argument type work unless you enable experimental features
Reflection was also not possible as I noticed, both annotations are removed at run time
spigot's feature flag api sucks tho
Although tbh I don't see how that would work
depends on how deep the concept goes
Blocks wouldn't work ofc
Yea, ik what it is
Like
This is one of those detatchments between upstream and mojang on how stuff is handled
Like, in retrospect what I said was dumb because I forgot about that caveat
a datapack could add a dimension that uses the experimental blocks in generation, so it has to add the experimental flag to that dimension to use them, while other dimensions remains fine without the experimental flag
Mojang could allow this at any time, since it's already checked using the world and not the global state (just right now the world redirects this to global state)
You can transfer blocks between dimensions yk
The confusion is how spigot, or, well, craftbukkit abuses ServerLevel
the way worlds works is really weird, and so it's not an issue
there is pretty much 0 reason why it needs to take a world, as that's not how this thing works
Yeah must say I'm starting to doubt whether I know how this works
Retaining @MinecraftExperimental at runtime would provide a quick (hacky) solution to this I suppose
private static final DynamicCommandExceptionType INVALID_STRUCTURE_ID_EXCEPTION = new DynamicCommandExceptionType(id -> MessageComponentSerializer.message().serialize(Component.translatable("structure_block.invalid_structure_name", id.toString())));
```is giving me `Invalid structure name '%s'` when I do `throw INVALID_STRUCTURE_ID_EXCEPTION.create(NamespacedKey key)`
Yes I am abusing a structure block translation key for structures, call me smart
Full code: https://pastes.dev/fd43Kant6Z
Any idea?
