Optional command arguments never get data

When I register a command using the following code:

CommandSpec spec = CommandSpec.builder()
            .description(Texts.of("Description"))
            .arguments(
                GenericArguments.remainingJoinedStrings(Texts.of("args"))
            )
            .executor(this)
            .build();
plugin.game.getCommandDispatcher().register(plugin, spec, name);

It works fine, and whenever I add in any text I call pull it out by accessing “args” on the CommandContext object. However when I do this:

CommandSpec spec = CommandSpec.builder()
            .description(Texts.of("Description"))
            .arguments(
                GenericArguments.optional(
                    GenericArguments.remainingJoinedStrings(Texts.of("args"))
                )
            )
            .executor(this)
            .build();
plugin.game.getCommandDispatcher().register(plugin, spec, name);

I get nothing, no matter how much text I type. Note that this happens if i change “remainingJoinedStrings” to just “string” as well.

This is the code I am using to access the data:

public CommandResult execute(CommandSource source, CommandContext context) {
    String argString = context.<String>getOne("args").orNull();

What am I missing here?

Note the main reason I want this to be optional is that sometimes the command needs to be run without any arguments.

I could be wrong, but I believe that remainingJoinedStrings can be used without optional and just return nothing, if there is no content. However, I don’t believe that using optional is the problem.

The part that confuses me is your use of .orNull(). What’s the purpose of this?

Optional#orNull() returns a null value, if there is nothing present. So looking at it, I would assume that you’re using this as a way to avoid unwrapping the Optional object, and just implement your own null check.

So, going from that, do you check if the value is null? What are you doing that you know the remaining strings aren’t being properly returned? Can we see the rest of the context of this code, to maybe see if the problem is somewhere else?

Optional:orNull

“Returns the contained instance if it is present; null otherwise. If the instance is known to be present, use get() instead.”

You are correct in saying that I am using this to avoid unwrapping.

This is the remainder of that function:

 public CommandResult execute(CommandSource source, CommandContext context) {
    String argString = context.<String>getOne("args").orNull();
    if (argString == null) {
        argString = "";
    }
    plugin.getLogger().info("Argument is " + argString);

    plugin.handleCommand(source,name,argString.split(" "));
    return CommandResult.success();
}

I’d hope that if there IS content, that remainingJoinedStrings would return it. This is not happening. Using my second example, if I enter the following:

/<command name> these are arguments to the command

Then the “args” parameter is always empty. If I use the first example (the one without the call to optional) and enter that same code, args will be “these are arguments to the command”

So the problem is with the GenericArguments#optional() method. Without it, if you don’t input any arguments, does the command fail?

Yes, the command will fail with something along the lines of

not enough parameters (not exactly the right error but close enough)
usage: /rank <args>

Note that I’ve also used a GenericArguments#string() method with the same results: Without optional, it will give me the first parameter entered. With optional, it gives nothing even if I enter a parameter.

As far as I can tell, this should work. But I’m not a Sponge developer, and the command service could just not be working, in this area.

I’ll raise this topic in #spongedev.

Ok thanks, I appreciate it. The plugin that this code is in is a port from Bukkit, and rather complicated, which is why I haven’t posted the entire thing (I’m relatively sure that the complication is NOT what is causing this issue). Let me know if a full working example is required and I will make something a little simpler that shows the same problem.

A neater way of this is to do:

String argString = context.<String>getOne("args").or("");
1 Like

Oh that is a lot nicer, thanks!

But it doesn’t seem like it answers your original question?

No, it’s just a structural change, it doesn’t fix the fact that the parameter still doesn’t exist. (I ran the code again with that change just to make sure)

Any update on this? If not I think I might start digging through the SpongeCommon code to see if I can figure out what’s going on. Either that or try to figure out a workaround, but I’ve been largely unsuccessful with that so far.

Not exactly sure but maybe this will help. https://github.com/trentech/EasyKits_Sponge/blob/master/src/com/gmail/trentech/EasyKits/Commands/Commands.java

https://github.com/trentech/EasyKits_Sponge/blob/master/src/com/gmail/trentech/EasyKits/Commands/CMDCooldown.java
I’m trying to do go through this post on my phone so I may be misinterpreting your question but I’ve had no problems with optional arguments

What sponge/forge build are you using? I wonder if I’m just using a broken build maybe?

If it’s working for you, then it’s probably just my problem. I’ll look into making a simple plugin to see if I can just get the concept working.

I’m using the latest and greatest sponge sponge-1.8-1446-2.1DEV-514 and forge-1.8-11.14.3.1466-universal, but I’ve tested this with earlier versions in the past and it worked fine as well. Maybe you have a forge/sponge version mismatch…

That may very well be the case, I got a warning about that when I first upgraded sponge, and then I THOUGHT I got the version of forge that matched but I could be wrong. Will see if that fixes the issue. Or maybe I’ll switch to SpongeVanilla.

Updating sponge and forge to the latest versions seems to have fixed the problem. Thanks for the help guys!

3 Likes