brigadier icon indicating copy to clipboard operation
brigadier copied to clipboard

[Bug] argument parser cannot parse string with ":"

Open DeStilleGast opened this issue 7 years ago • 6 comments

So while I was playing with this lib, I got it slowly working with a few commands except one.

I have tried every StringArgumentType (word and string) but it cannot read arguments with :

errors trown with toast123:toast456 word and string: throws: com.mojang.brigadier.exceptions.CommandSyntaxException: Expected whitespace to end one argument, but found trailing data at position 16: ...t toast123<--[HERE]

Note: I can't use greedyString since I use more arguments after this argument. It's late in the evening, may have overlooked something or I missed a class that I could use.

DeStilleGast avatar Nov 07 '18 23:11 DeStilleGast

@DeStilleGast I don't think there's enough information here to help you effectively.

Can you post a code example of the command registration that you were attempting to parse, and the full command that you were entering?

As well as what you expected to happen, (clearly in this case, not throw errors) but it looks like this is only one small piece of the puzzle.

ryantheleach avatar Nov 08 '18 03:11 ryantheleach

@ryantheleach yeah sure, makes sense

the code for the command is:

commandDispatcher.register(
	literal("checkit")
	.then(
		argument("server", word())
			.executes(c -> {
				String server = c.getArgument("server", String.class);
				int port = 25565;

				if(server.contains(":")) {
					String[] split = server.split(":");
					server = split[0];
					port = Integer.parseInt(split[1]);
				}

				checkWhitelisted(c.getSource(), server, port, c.getSource().getUsername());
				return 1;
			})
			.then(argument("user", string())
				.executes(c -> {
					String server = c.getArgument("server", String.class);
					int port = 25565;

					if(server.contains(":")) {
						String[] split = server.split(":");
						server = split[0];
						port = Integer.parseInt(split[1]);
					}

					checkWhitelisted(c.getSource(), server, port, c.getArgument("user", String.class));
					return 1;
				})))
);

and the command that I try to execute (command prefix removed): checkit 127.0.0.1:25566 what this command basicly should do is that is checks the database if a user is whitelisted or not (reply is done in the function itself)

current workaround is to use checkit "127.0.0.1:25566" but that can get annoying and confusing

DeStilleGast avatar Nov 08 '18 10:11 DeStilleGast

The best solution here would be a custom argument so you can validate input quicker and do the splitting of port at parse-time instead of execute-time.

If you need to use string, you'll have to quote it. checkit "127.0.0.1:25566" - unquoted strings can only contain a limited set of characters.

Dinnerbone avatar Nov 08 '18 10:11 Dinnerbone

@Dinnerbone I really don't need a string for it, I just parse a ip and port from a string with optional port option. I tried to make a custom argument, thought first it was going to be hard, but it is easier then it looks.

Created my own IpArgumentType and it works pretty.

My code for future people (it's maybe not pretty, but it works well): Class IpArgumentType

public class IpArgumentType implements ArgumentType<Ip> {

    @Override
    public <S> Ip parse(StringReader reader) throws CommandSyntaxException {
        String input = reader.getRemaining().split(" ")[0];
        reader.setCursor(reader.getCursor() + input.length());

        return new Ip(input);
    }

    @Override
    public <S> CompletableFuture<Suggestions> listSuggestions(CommandContext<S> context, SuggestionsBuilder builder) {
        return null;
    }

    @Override
    public Collection<String> getExamples() {
        return Arrays.asList("127.0.0.1", "127.0.0.1:25567");
    }
}

Class Ip:

public class Ip {

    private String ip;
    private int port = 25565; //default port

    public Ip(String ip) {
        this.ip = ip;

        if(ip.contains(":")) {
            String[] split = ip.split(":");
            this.ip = split[0];
            try {
                port = Integer.parseInt(split[1]);
            }catch (NumberFormatException ex){
                throw new NumberFormatException(String.format("%s is not a number !!", split[1]));
            }
        }
    }

    public Ip(String ip, int port) {
        this.ip = ip;
        this.port = port;
    }

    public String getIp() {
        return ip;
    }

    public int getPort() {
        return port;
    }
}

DeStilleGast avatar Nov 08 '18 12:11 DeStilleGast

but my issue is fixed, keep this bug open or can it be closed ?

DeStilleGast avatar Nov 08 '18 12:11 DeStilleGast

This should be closed as 'not an issue' or the equivalent.

Technically it's not a bug because : is not part of the syntax for an unquoted string (though this is undocumented):

https://github.com/Mojang/brigadier/blob/cf754c4ef654160dca946889c11941634c5db3d5/src/main/java/com/mojang/brigadier/StringReader.java#L169-L175

The solution is (as was suggested) to create a custom argument that can parse values with : in them.

Pharap avatar Nov 09 '21 16:11 Pharap