User Tools

Site Tools


Sidebar

← Go back to the homepage

Fabric Tutorials

Setup

Basics

These pages are essential must-reads when modding with Fabric, and modding Minecraft in general, if you are new to modding, it is recommended you read the following.

Items

Blocks and Block Entities

Data Generation

World Generation

Commands

These pages will guide you through Mojang's Brigadier library which allows you to create commands with complex arguments and actions.

Events

These pages will guide you through using the many events included in Fabric API, and how to create your own events for you or other mods to use.

Entities

Fluids

Mixins & ASM

These pages will guide you through the usage of SpongePowered's Mixin library, which is a highly complex topic. We recommend you read these pages thoroughly.

Miscellaneous

Yarn

Contribute to Fabric

tutorial:command_argument_types

Command Argument Types

Brigadier has support for custom argument types and this section goes into showing how to create a simple argument type.

Warning: Custom arguments require client mod installation to be registered correctly! If you are making a server plugin, consider using existing argument type and a custom suggestions provider instead.

For this example we will create a UuidArgumentType.

First create a class which extends ArgumentType. Note that ArgumentType is a generic, so the generic will define what type the ArgumentType will return

  1. public class UuidArgumentType implements ArgumentType<UUID> {

ArgumentType requires you to implement the parse method, the type it returns will match with the Generic type.

@Override
public UUID parse(StringReader reader) throws CommandSyntaxException {

This method is where all of your parsing will occur. Either this method will return the object based on the arguments provided in the command line or throw a CommandSyntaxException and parsing will fail.

Next you will store the current position of the cursor, this is so you can substring out only the specific argument. This will always be at the beginning of where your argument appears on the command line.

  1. int argBeginning = reader.getCursor(); // The starting position of the cursor is at the beginning of the argument.
  2. if (!reader.canRead()) {
  3. reader.skip();
  4. }

Now we grab the entire argument. Depending on your argument type, you may have a different criteria or be similar to some arguments where detecting a { on the command line will require it to be closed. For a UUID we will just figure out what cursor position the argument ends at.

  1. while (reader.canRead() && reader.peek() != ' ') { // peek provides the character at the current cursor position.
  2. reader.skip(); // Tells the StringReader to move it's cursor to the next position.
  3. }

Then we will ask the StringReader what the current position of the cursor is an substring our argument out of the command line.

  1. String uuidString = reader.getString().substring(argBeginning, reader.getCursor());

Now finally we check if our argument is correct and parse the specific argument to our liking, and throwing an exception if the parsing fails.

  1. try {
  2. UUID uuid = UUID.fromString(uuidString); // Now our actual logic.
  3. return uuid; // And we return our type, in this case the parser will consider this argument to have parsed properly and then move on.
  4. } catch (Exception ex) {
  5. // UUIDs can throw an exception when made by a string, so we catch the exception and repackage it into a CommandSyntaxException type.
  6. // Create with context tells Brigadier to supply some context to tell the user where the command failed at.
  7. // Though normal create method could be used.
  8. throw new SimpleCommandExceptionType(Text.literal(ex.getMessage())).createWithContext(reader);
  9. }

The ArgumentType is done, however your client will refuse the parse the argument and throw an error. This is because the server will tell the client what argument type the command node is. And the client will not parse any argument types it does not know how to parse. To fix this we need to register an ArgumentSerializer. Within your ModInitializer. For more complex argument types, you may need to create your own ArgumentSerializer.

  1. ArgumentTypeRegistry.registerArgumentType(new Identifier("tutorial", "uuid"), UuidArgumentType.class, ConstantArgumentSerializer.of(UuidArgumentType::uuid));
  2. // The argument should be what will create the ArgumentType.

And here is the whole ArgumentType:

UuidArgumentType.java
  1. import com.mojang.brigadier.StringReader;
  2. import com.mojang.brigadier.arguments.ArgumentType;
  3. import com.mojang.brigadier.context.CommandContext;
  4. import com.mojang.brigadier.exceptions.CommandSyntaxException;
  5. import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
  6. import net.minecraft.text.Text;
  7. import net.minecraft.util.SystemUtil;
  8.  
  9. import java.util.ArrayList;
  10. import java.util.Collection;
  11. import java.util.UUID;
  12.  
  13. /**
  14.  * Represents an ArgumentType that will return a UUID.
  15.  */
  16. public class UuidArgumentType implements ArgumentType<UUID> {
  17. public static UuidArgumentType uuid() {
  18. return new UuidArgumentType();
  19. }
  20.  
  21. public static <S> UUID getUuid(String name, CommandContext<S> context) {
  22. // Note that you should assume the CommandSource wrapped inside of the CommandContext will always be a generic type.
  23. // If you need to access the ServerCommandSource make sure you verify the source is a server command source before casting.
  24. return context.getArgument(name, UUID.class);
  25. }
  26.  
  27. private static final Collection<String> EXAMPLES = SystemUtil.consume(new ArrayList<>(), list -> {
  28. list.add("765e5d33-c991-454f-8775-b6a7a394c097"); // i509VCB: Username The_1_gamers
  29. list.add("069a79f4-44e9-4726-a5be-fca90e38aaf5"); // Notch
  30. list.add("61699b2e-d327-4a01-9f1e-0ea8c3f06bc6"); // Dinnerbone
  31. });
  32.  
  33. @Override
  34. public UUID parse(StringReader reader) throws CommandSyntaxException {
  35. int argBeginning = reader.getCursor(); // The starting position of the cursor is at the beginning of the argument.
  36. if (!reader.canRead()) {
  37. reader.skip();
  38. }
  39.  
  40. // Now we check the contents of the argument till either we hit the end of the command line (When canRead becomes false)
  41. // Otherwise we go till reach reach a space, which signifies the next argument
  42. while (reader.canRead() && reader.peek() != ' ') { // peek provides the character at the current cursor position.
  43. reader.skip(); // Tells the StringReader to move it's cursor to the next position.
  44. }
  45.  
  46. // Now we substring the specific part we want to see using the starting cursor position and the ends where the next argument starts.
  47. String uuidString = reader.getString().substring(argBeginning, reader.getCursor());
  48. try {
  49. UUID uuid = UUID.fromString(uuidString); // Now our actual logic.
  50. return uuid; // And we return our type, in this case the parser will consider this argument to have parsed properly and then move on.
  51. } catch (Exception ex) {
  52. // UUIDs can throw an exception when made by a string, so we catch the exception and repackage it into a CommandSyntaxException type.
  53. // Create with context tells Brigadier to supply some context to tell the user where the command failed at.
  54. // Though normal create method could be used.
  55. throw new SimpleCommandExceptionType(Text.literal(ex.getMessage())).createWithContext(reader);
  56. }
  57. }
  58.  
  59. @Override
  60. public Collection<String> getExamples() { // Brigadier has support to show examples for what the argument should look like, this should contain a Collection of only the argument this type will return. This is mainly used to calculate ambiguous commands which share the exact same
  61. return EXAMPLES;
  62. }
  63. }
tutorial/command_argument_types.txt · Last modified: 2022/08/08 02:20 by solidblock