Optional first player argument

I want to make a teleport command with the usage /tp [<player>] <target>. Is this possible using generic arguments?

I tried
GenericArguments.optional(GenericArguments.player(Text.of("player"))), GenericArguments.player(Text.of("target")));
but when calling with only one argument, the “player” element catches the argument and “target” doesn’t seem able to backtrack, yielding a “Not enough arguments” error.

I could of course swap the arguments but /tp <target> [<player>] seems less intuitive.

You almost on the right track, the way to do this, inside your CommandSpec as you know,

GenericArguments.player(Text.of("target")),
GenericArguments.optional(GenericArguments.onlyOne(GenericArguments.player("player")))

Then obviously to get the objects inside the executor, I like to use optionals but you dont have to

Optional<Player> opTarget = args.<Player>getOne("target");
Optional<Player> opPlayer = args.<Player>getOne("player");

And then check if opPlayer was present. You can obviously change around the names but this is basically what you want to do.

Damn it, saw it was 4 hours old and started crafting a reply, instantly ninja’d.

2 Likes

Lol yeah I had .seq because i copied from a project I had done before but yes you do not need that.

New reply because my edits were getting messy.

I believe what you are looking for is GenericArguments.playerOrSource

This will fill in a missing player argument with the current player.

So having GenericArguments.playerOrSource and GenericArguments.player should fix this for you.

1 Like

Thanks for your input, but those arguments create the usage /tp <target> [<player>]. I prefer the player that is to be teleported is first.

As a temporary fix I’ve got the usage /tp <player> [<target>] where I in the executor treat <player> as <target> if <target> isn’t set.

While that produces the correct usage /tp [<player>] <target>, I still get an “Not enough arguments” error when using only one argument

This is a bit of a hack, but you can reverse the argument order.

args(player, player)

/tp player1 player2

/tp player1

if(player2.isabsent) player2 = player1
if(commandsource is a player) player 1 = (player) commandSource
else {
throw new CommandException(Text.of(“Missing player argument.”))
}

There’s also probably a solution by wrapping something in an optionalWeak, but I’m not experienced enough to know what without an IDE to test with.

Thanks, that’s what I’ve done. My issue here isn’t really implementing the command, it’s making the command usage in /help look proper. I’d like it to say /tp [<player>] <target>. I guess it’s not extremely important, but it does bug me :yum:

Hm, sucks that the commandspec builder doesn’t let you override the usage.

You should be able to extend seq and just delegate everything except the getUsage text, which you can define however you want.

But hopefully someone else has a better solution.

I wonder how hard it would be to create an argument that reverses the parsing order.

We should have a version of optional that is only present when explicitly filled.