JorelAli / CommandAPI

A Bukkit/Spigot API for the command UI introduced in Minecraft 1.13

Home Page:https://commandapi.jorel.dev

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

translatable CommandSyntaxException message on velocity

Robsutar opened this issue · comments

Description

I didn't find any implementation of a PlayerArgument for the CommandApi version of velocity, so I implemented this one:

public class PlayerArgument extends Argument<Player> {
    public PlayerArgument(String nodeName) {
        super(nodeName, StringArgumentType.word());
        replaceSuggestions(ArgumentSuggestions.strings((info)->
                VGProxy.server().getAllPlayers().stream().map(Player::getUsername).toArray(String[]::new))
        );
    }

    @Override
    public Class<Player> getPrimitiveType() {
        return Player.class;
    }

    @Override
    public CommandAPIArgumentType getArgumentType() {
        return CommandAPIArgumentType.PLAYER;
    }

    @Override
    public <CommandSourceStack> Player parseArgument(CommandContext<CommandSourceStack> cmdCtx, String key, CommandArguments previousArgs) throws CommandSyntaxException {
        var opt = PrettyCoolVelocityPlugin.server().getPlayer(cmdCtx.getArguments().get(key).getResult().toString());
        if (opt.isPresent()) return opt.get();
        else throw new CommandSyntaxException(
                new SimpleCommandExceptionType(new LiteralMessage("That player does not exist")),
                new LiteralMessage("That player does not exist"));
    }
}

Instead of directly using the English phrase, is it possible to use its translation key? In this case I would like to use "argument.player.unknown" key.
I tried using VelocityBrigadierMessage, but the translation key is passed as text to the player.

I'm not super familiar with how Adventure Components work, but I think this code works for what you want:

throw new SimpleCommandExceptionType(new VelocityBrigadierMessage(Component.translatable("argument.player.unknown"))).create();

Component#translatable is how you get a translated Component in the Adventure API, and VelocityBrigadierMessage converts that Component to a Brigadier Message. Note that you can also use SimpleCommandExceptionType#create to avoid that thing where you've created the LiteralMessage twice.

Thanks for the suggestion, but I had already tested this before:

throw new SimpleCommandExceptionType(VelocityBrigadierMessage.tooltip(Component.translatable("argument.player.unknown"))).create()

but the implementation of VelocityBrigadierMessage's getString is this:

  /**
   * Returns the message as a plain text.
   *
   * @return message as plain text
   */
  @Override
  public String getString() {
    return PlainTextComponentSerializer.plainText().serialize(message);
  }

I took a look at how this is implemented in the Forge package, and there is a specific class that extends Message from the native Minecraft client library, and I didn't find anything similar here in velocity. Which is strange, because there are translatable messages in the other native CommandApi-velocity syntax errors.

Hmm, #velocity-dev in the Paper Discord might be a better place for this question. Unless there's some specific backend thing the CommandAPI can help access to make this possible, they definitely know more about this than I do.

It looks like Velocity only loads the translation keys from this file, so maybe you need to load and register the translations on the proxy yourself (Described here: https://docs.papermc.io/velocity/dev/component-api/i18n#resourcebundle)?

However, it does look like it is possible to send translation keys to the client for them to decode: https://wiki.vg/Text_formatting#Translatable_content. So, maybe it's a bug in Velocity where VelocityBrigadierMessage doesn't work with translations.

I sent a message there but no one gave me a solution... Apparently Velocity's CommandApi doesn't have translatable messages, I tested it with a syntax error, it works in the Bukkit package, but not in Velocity's (it's only in English), is there any plan to implement translatable texts in CommandApi in the future?

I believe this is something that Velocity would need to add.

As far as I can tell, on the Minecraft server when a CommandSyntaxException is thrown while executing a player's command, the Brigadier Message within the CommandSyntaxException is not flattened into a String. If the Message represents a translatable net.minecraft.network.chat.Component, it is sent to the client formatted as described here: https://wiki.vg/Text_formatting#Translatable_content.

On Velocity, instead of using CommandSyntaxException#getMessage here, they should probably use CommandSyntaxException#getRawMessage. If the Brigadier Message is a VelocityBrigadierMessage with a translatable net.kyori.adventure.text.Component, they should serialize it as such for the client to decode.

I don't think this would be something for the CommandAPI to do. Sending packets to the player is probably something that Velocity should implement. Plugins are supposed to interact with Velocity through the API provided in com.velocitypowered.velocity-api, whereas all the code for sending packets is within the com.velocitypower.velocity-proxy dependency. While it is technically possible to write code to interact with com.velocitypower.velocity-proxy, I don't believe it's published to maven-central — so definitely not a recommended action.

I plan to create an issue in the Velocity repo about this. I can't test it right now, but I believe this code should reproduce the "issue" independent of the CommandAPI:

server.getCommandManager().register(new BrigadierCommand(
	LiteralArgumentBuilder.<CommandSource>literal("command").then(
		RequiredArgumentBuilder.<CommandSource, String>argument("player", StringArgumentType.word())
			.suggests((context, builder) -> {
				server.getAllPlayers().stream().map(Player::getUsername).forEach(builder::suggest);
				return builder.buildFuture();
			})
			.executes(context -> {
				String playerName = context.getArgument("player", String.class);
				Optional<Player> optionalPlayer = server.getPlayer(playerName);

				if(!optionalPlayer.isPresent()) 
					throw new SimpleCommandExceptionType(VelocityBrigadierMessage.tooltip(Component.translatable("argument.player.unknown"))).create();
					
				optionalPlayer.get().sendMessage(Component.text("You were the target of the command"));

				return 1;
			})
	)
));

I have created an issue for this in the Velocity repo: PaperMC/Velocity#1294

I have created an issue for this in the Velocity repo: PaperMC/Velocity#1294

fixed

👍 I can confirm that my test case in PaperMC/Velocity#1294 works as expected using Velocity build 378. I expect that should solve your issue as well @Robsutar.

Working perfectly in the build 378 using the code:

throw new SimpleCommandExceptionType(VelocityBrigadierMessage.tooltip(Component.translatable("argument.player.unknown"))).create();

Thank you for your time and attention!