Brigadier supports command exceptions which can be used to end a command such as if an argument didn't parse properly or the command failed to execute, as well as including richer details of the failure.
There are two type of command exceptions:
CommandSyntaxException
: provided by Brigadier. It should have an exception type, and created through create(…)
or createWithContext(…)
. It does not belong to RuntimeException
, so when thrown, it must be caught properly, or added in the method signature.CommandException
(removed since 1.20.3): provided in Minecraft, and used in less cases. It belongs to RuntimeException
. You can directly create it with a Text
as parameter.
The two main types of CommandSyntaxException
are dynamic and simple exception types, of which you can call create()
to create the exception to throw it. These exceptions also allow you to specify the context in which the exception was thrown using createWithContext(ImmutableStringReader)
, which builds the error message to point to where on the inputted command line the error occured.
Below is a coin flip command to show an example of exceptions in use.
dispatcher.register(literal("coinflip") .executes(ctx -> { if(random.nextBoolean()) { // If heads succeed. ctx.getSource().sendFeedback(() -> Text.translatable("coin.flip.heads"), true); return Command.SINGLE_SUCCESS; } throw new CommandException(Text.translatable("coin.flip.tails")); }));
CommandException
is removed since 1.20.3.
If you use CommandSyntaxException
, you should add a SimpleCommandExceptionType
first. It is usually stored as fields, so this example presents the whole class.
public class ExampleMod implements ModInitializer { public static final SimpleCommandExceptionType COIN_FLIP_TAILS = new SimpleCommandExceptionType(Text.translatable("coin.flip.tails")); @Override public void onInitialize() { CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> dispatcher.register(literal("coinflip") .executes(ctx -> { Random random = ctx.getSource().getWorld().getRandom(); if (random.nextBoolean()) { // If heads succeed. ctx.getSource().sendFeedback(() -> Text.translatable("coin.flip.heads"), true); return Command.SINGLE_SUCCESS; } throw COIN_FLIP_TAILS.create(); }))); } }
Sometimes you may use DynamicCommandExceptionType
to accept complex exceptions. For example:
public class ExampleMod implements ModInitializer { public static final DynamicCommandExceptionType COIN_FLIP_TAILS = new DynamicCommandExceptionType(o -> Text.translatable("coin.flip.tails", o)); @Override public void onInitialize() { CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> dispatcher.register(literal("coinflip") .executes(ctx -> { Random random = ctx.getSource().getWorld().getRandom(); if (random.nextBoolean()) { // If heads succeed. ctx.getSource().sendFeedback(() -> Text.translatable("coin.flip.heads"), true); return Command.SINGLE_SUCCESS; } throw COIN_FLIP_TAILS.create(ctx.getSource().getDisplayName()); }))); } }
There are more Dynamic exception types which each take a different amount of arguments into account (Dynamic2CommandExceptionType
, Dynamic3CommandExceptionType
, Dynamic4CommandExceptionType
, DynamicNCommandExceptionType
). You should remember that the Dynamic exceptions takes an object as an argument so you may have to cast the argument for your use.
There are some vanilla exceptions. Some can be found in CommandSyntaxException.BUILT_IN_EXCEPTIONS.<exception type>()
.