tutorial:commands
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revisionNext revisionBoth sides next revision | ||
tutorial:commands [2019/09/18 00:51] – Add Chainable commands redirect info and open section for custom arguments. i509vcb | tutorial:commands [2023/11/18 10:59] – [Why does my code not compile] solidblock | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | Licensing: The code in this article is licensed under the " | ||
+ | |||
====== Creating Commands ====== | ====== Creating Commands ====== | ||
- | Creating commands can allow a mod developer to add functionality that a player | + | Creating commands can allow a mod developer to add functionality that can used through a command. This tutorial will teach you how to register commands, and the general |
- | This tutorial will teach you how to register commands, and the command structure of Brigadier | + | |
- | ===== Registering Commands ===== | + | Note: All code written here was written for 1.19.2. For old versions, some versions and mappings may differ. |
- | If you just want to see how to register commands you've come to the right place here. | + | ===== What is Brigadier? ===== |
- | Registering commands | + | Brigadier |
- | The '' | + | The source code for brigadier can be found here: https:// |
- | The dedicated flag if set to true will tell Fabric to only register the command on a '' | + | ===== The '' |
- | Below are a few examples | + | In Minecraft, '' |
- | <code java [enable_line_numbers=" | + | The single method in '' |
- | CommandRegistry.INSTANCE.register(false, | + | |
- | + | ||
- | CommandRegistry.INSTANCE.register(false, | + | |
- | TutorialCommand.register(dispatcher); | + | |
- | TutorialHelpCommand.register(dispatcher); | + | |
- | }); | + | |
- | + | ||
- | CommandRegistry.INSTANCE.register(true, dispatcher -> { // Or directly registering | + | |
- | dispatcher.register(LiteralArgumentBuilder.literal(" | + | |
- | }); | + | |
- | </ | + | |
- | ==== A very basic command ==== | + | Like other functional interfaces, it is usually used as a lambda or a method reference: |
- | Wait isn't this the exact same command from the Brigadier tutorial? Well yes it is but it is here to help explain the structure of a command. | + | <code java> |
- | + | Command< | |
- | <code java [enable_line_numbers=" | + | return |
- | // The root of the command. This must be a literal argument. | + | }; |
- | dispatcher.register(CommandManager.literal(" | + | |
- | // Then add an argument named bar that is an integer | + | |
- | .then(CommandManager.argument(" | + | |
- | // The command to be executed if the command " | + | |
- | .executes(ctx | + | |
- | System.out.println(" | + | |
- | // Return a result. -1 is failure, 0 is a pass and 1 is success. | + | |
- | return 1; | + | |
- | })) | + | |
- | | + | |
- | .executes(ctx -> { | + | |
- | System.out.println(" | + | |
- | | + | |
- | }) | + | |
- | ); | + | |
</ | </ | ||
- | The main process registers the command " | + | In vanilla Minecraft, they are usually used as method references, such as static methods named '' |
- | Since the root node must be literal, The sender must enter the exact same sequence of letters to execute the command, so " | + | |
- | ===== Brigadier Explained ===== | + | The integer can be considered the result of the command. Typically negative values mean a command has failed and will do nothing. A result of '' |
- | Brigadier starts with the '' | ||
- | The trunk of the tree is the CommandDispatcher. | ||
- | The register(LiteralArgumentBuilder) methods specify the beginning of branches with the following then methods specifying the shape of length of the branches. | ||
- | The executes blocks can be seen at the leaves of the tree where it ends and also supplies the outcome of the system. | ||
- | The execute blocks specify the command to be ran. As Brigadier' | + | ==== What can the ServerCommandSource do? ==== |
- | ==== CommandContexts ==== | + | A '' |
- | When a command is ran, Brigadier provides a CommandContext to the command that is ran. | + | <code java [enable_line_numbers=" |
- | The CommandContext contains all arguments and other objects such as the inputted String and the '' | + | // Get the source. This will always work. |
+ | final ServerCommandSource | ||
- | ==== Arguments ==== | + | // Unchecked, may be null if the sender was the console or the command block. |
+ | final @Nullable Entity sender | ||
- | The arguments in Brigadier both parse and error check any inputted arguments. | + | // Will throw an exception if the executor of the command was not an Entity. |
- | Minecraft creates some special arguments for it's own use such as the '' | + | // The result of this could contain a player. Also will send feedback telling |
+ | // This method will require your methods to throw a CommandSyntaxException. | ||
+ | // The entity options in ServerCommandSource could return a CommandBlock entity, any living entity | ||
+ | final @NotNull Entity sender2 = source.getEntityOrThrow(); | ||
- | You could do the long method | + | // null if the executor |
- | This also works for getting arguments, which shortens the already long '' | + | final @Nullable ServerPlayerEntity player = source.getPlayer(): |
- | This also works for Minecraft' | + | |
- | And your imports would look something like this: | + | // Will throw an exception if the executor of the command was not explicitly a Player. |
- | <code java [enable_line_numbers=" | + | // Also will send feedback telling the sender of the command |
- | import static com.mojang.brigadier.arguments.StringArgumentType.getString; | + | // This method will require your methods to throw a CommandSyntaxException. |
- | import static com.mojang.brigadier.arguments.StringArgumentType.word; | + | final @NotNull ServerPlayerEntity player = source.getPlayerOrThrow(); |
- | import static net.minecraft.server.command.CommandManager.literal; | + | |
- | import static net.minecraft.server.command.CommandManager.argument; | + | |
- | import static net.minecraft.server.command.CommandManager.*; // Import everything | + | |
- | </ | + | |
- | Brigadier' | + | // Gets the sender' |
+ | // This could be the location of the entity/ | ||
+ | final Vec3d position = source.getPosition(); | ||
- | Minecraft' | + | // Gets the world the sender is within. The console' |
+ | final ServerWorld world = source.getWorld(); | ||
- | ==== Suggestions ==== | + | // Gets the sender' |
+ | final Vec2f rotation | ||
- | Suggestions can be provided | + | // Access |
- | < | + | final MinecraftServer server = source.getServer(); |
- | SUMMONABLE_ENTITIES | + | |
- | AVAILIBLE_SOUNDS | + | |
- | ALL_RECIPES | + | |
- | ASK_SERVER | + | |
- | </ | + | |
- | Loot tables specify their own SuggestionProvider inside LootCommand for example. | + | // The name of the command source. This could be the name of the entity, player, |
+ | // the name of a CommandBlock that has been renamed before being placed down, or in the case of the Console, " | ||
+ | final String name = source.getName(); | ||
- | The example below is a dynamically changing SuggestionProvider that lists several words for a StringArgumentType to demonstrate how it works: | + | // Returns true if the source of the command has a certain permission level. |
- | <code java [enable_line_numbers=" | + | // This is based on the operator status of the sender. |
- | public static SuggestionProvider< | + | // (On an integrated server, the player must have cheats enabled |
- | return (ctx, builder) -> getSuggestionsBuilder(builder, | + | final boolean b = source.hasPermissionLevel(int level); |
- | } | + | |
- | + | ||
- | private static CompletableFuture< | + | |
- | String remaining = builder.getRemaining().toLowerCase(Locale.ROOT); | + | |
- | + | ||
- | | + | |
- | return Suggestions.empty(); // No suggestions | + | |
- | } | + | |
- | + | ||
- | for (String str : list) { // Iterate through | + | |
- | if (str.toLowerCase(Locale.ROOT).startsWith(remaining)) { | + | |
- | | + | |
- | } | + | |
- | } | + | |
- | return builder.buildFuture(); // Create the CompletableFuture containing all the suggestions | + | |
- | } | + | |
</ | </ | ||
- | The SuggestionProvider is a FunctionalInterface that returns a CompletableFuture containing a list of suggestions. These suggestions are given to client as a command | + | ===== Register |
- | Though remember these are suggestions. The inputted command may not contain an argument you suggested so you still have to parse check inside | + | Commands |
- | To use the suggestion you would append it right after the argument you want to recommend arguments for. This can be any argument | + | The event should |
- | <code java [enable_line_numbers=" | + | To simplify the code, it is highly recommended to '' |
- | argument(argumentName, | + | <code java> |
- | .suggests(CompletionProviders.suggestedStrings()) | + | import static net.minecraft.server.command.CommandManager.*; |
- | | + | |
</ | </ | ||
- | ==== Requires ==== | + | In the mod initializer, |
- | + | ||
- | Lets say you have a command you only want operators to be able to execute. This is where the '' | + | |
- | + | ||
- | For example this may look like the following: | + | |
<code java [enable_line_numbers=" | <code java [enable_line_numbers=" | ||
- | dispatcher.register(literal(" | + | public class ExampleMod implements ModInitializer { |
- | .requires(source -> source.hasPermissionLevel(4)) | + | @Override |
- | .executes(ctx -> { | + | public void onInitialize() { |
- | ctx.getSource().sendFeedback(new LiteralText("You are an operator", false)); | + | CommandRegistrationCallback.EVENT.register((dispatcher, |
- | return | + | .executes(context |
- | }); | + | // For versions below 1.19, replace " |
- | </code> | + | context.getSource().sendFeedback(Text.literal("Called /foo with no arguments"), false); |
+ | // For versions since 1.20, please use the following, which is intended to avoid creating Text objects if no feedback is needed. | ||
+ | | ||
- | This command will only execute if the Source of the command is a level 4 operator at minimum. If the predicate returns false, then the command will not execute. Also this has the side effect of not showing this command in tab completion to anyone who is not a level 4 operator. | + | |
- | + | }))); | |
- | ==== Exceptions ==== | + | } |
- | + | } | |
- | 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. | + | |
- | + | ||
- | All the exceptions from Brigadier are based on the CommandSyntaxException. The two main types of exceptions Brigadier provides are Dynamic and Simple exception types, of which you must '' | + | |
- | Below is a coin flip command to show an example of exceptions in use. | + | |
- | + | ||
- | <code java [enable_line_numbers=" | + | |
- | dispatcher.register(CommandManager.literal(" | + | |
- | .executes(ctx -> { | + | |
- | Random random = new Random(); | + | |
- | + | ||
- | if(random.nextBoolean()) { // If heads succeed. | + | |
- | ctx.getSource().sendMessage(new TranslateableText(" | + | |
- | return | + | |
- | } | + | |
- | throw new SimpleCommandExceptionType(new TranslateableText(" | + | |
- | })); | + | |
</ | </ | ||
- | Though | + | **Please ensure |
- | <code java [enable_line_numbers=" | + | In the '' |
- | DynamicCommandExceptionType used_name = new DynamicCommandExceptionType(name -> { | + | |
- | return new LiteralText(" | + | |
- | }); | + | |
- | </code> | + | |
- | There are more Dynamic exception types which each take a different amount | + | If the command fails, instead |
- | You should remember that the Dynamic exceptions takes an object as an argument so you may have to cast the argument | + | |
- | ==== Redirects (Aliases) ==== | + | To execute this command, you must type ''/ |
- | Redirects are Brigadier' | + | ===== Registration environment ===== |
+ | If desired, you can also make sure a command | ||
- | <code java [enable_line_numbers=" | + | <yarncode |
- | public | + | public |
- | | + | |
- | | + | public void onInitialize() { |
- | .redirect(node)); // Alias 1, redirect to main command | + | |
- | | + | |
- | .redirect(node)); // Alias 2, redirect to main command | + | ...; |
+ | } | ||
+ | }); | ||
+ | } | ||
} | } | ||
+ | </ | ||
- | public | + | ===== Static Imports ===== |
- | return dispatcher.register(literal(" | + | In the example above, the use of static |
- | .then(argument(" | + | |
- | | + | |
- | .executes(ctx -> { | + | |
- | return execute(ctx.getSource(), | + | |
- | })))); | + | |
- | } | + | |
- | </ | + | |
- | + | ||
- | The redirect registers a branch into the command tree, where the dispatcher is told when executing a redirected command to instead look on a different branch for more arguments and executes blocks. The literal argument that the redirect is placed on will also rename first literal on the targeted branch in the new command. | + | |
- | + | ||
- | Redirects do not work in shortened aliases such as '' | + | |
- | + | ||
- | ==== Redirects (Chainable Commands) ==== | + | |
- | Commands such as ''/ | + | |
+ | Below is an example of some static imports: | ||
<code java [enable_line_numbers=" | <code java [enable_line_numbers=" | ||
- | LiteralCommandNode< | + | // getString(ctx, "string") |
- | LiteralCommandNode< | + | import static com.mojang.brigadier.arguments.StringArgumentType.getString; |
- | // You can register under the same literal more than once, it will just register new parts of the branch as shown below if you register a duplicate branch an error will popup in console warning of conflicting commands but one will still work. | + | // word() |
- | .then(literal(" | + | import static com.mojang.brigadier.arguments.StringArgumentType.word; |
- | .then(literal(" | + | // literal(" |
- | | + | import static net.minecraft.server.command.CommandManager.literal; |
- | .then(literal("short") | + | // |
- | .redirect(root))) // Return to root for chaining | + | import static net.minecraft.server.command.CommandManager.argument; |
- | .then(literal(" | + | // Import everything in the CommandManager |
- | | + | import static net.minecraft.server.command.CommandManager.*; |
- | ctx.getSource().sendFeedback(new LiteralText(" | + | |
- | | + | |
- | }))); | + | |
</ | </ | ||
- | The redirect can also modify the CommandSource. | ||
- | <code java [enable_line_numbers=" | + | Note: Please be sure you use the '' |
- | .redirect(rootNode, (commandContext_1x) -> { | + | |
- | return ((ServerCommandSource) commandContext_1x.getSource()).withLookingAt(Vec3ArgumentType.getVec3(commandContext_1x, | + | |
- | }) | + | |
- | </ | + | |
- | ===== ServerCommandSource ===== | + | Brigadier' |
- | What if you wanted a command | + | Minecraft' |
- | <code java [enable_line_numbers=" | + | ===== Add Requirements ===== |
- | ServerCommandSource source | + | |
- | // Get the source. This will always work. | + | |
- | Entity sender = source.getEntity(); | + | Let's say you have a command that you only want operators to be able to execute. This is where the '' |
- | // Unchecked, may be null if the sender was the console. | + | |
- | Entity sender2 = source.getEntityOrThrow(); | + | For example |
- | // Will end the command if the source of the command was not an Entity. | + | |
- | // The result of this could contain a player. Also will send feedback telling the sender of the command that they must be an entity. | + | |
- | // This method will require your methods to throw a CommandSyntaxException. | + | |
- | // The entity options in ServerCommandSource could return a CommandBlock entity, any living entity or a player. | + | |
- | ServerPlayerEntity player | + | <code java [enable_line_numbers=" |
- | // Will end the command if the source | + | dispatcher.register(literal(" |
+ | | ||
+ | | ||
+ | ctx.getSource().sendFeedback(() -> Text.literal(" | ||
+ | return 1; | ||
+ | }); | ||
</ | </ | ||
- | The ServerCommandSource also provides other information about the sender | + | This command will only execute if the source |
- | <code java [enable_line_numbers=" | + | To create commands that only level 4 operators |
- | source.getPosition(); | + | |
- | // Get's the sender' | + | |
- | source.getWorld(); | + | ===== Arguments ===== |
- | // Get's the world the sender is within. The console' | + | |
- | source.getRotation(); | + | Arguments are used in most of commands. Sometimes they can be optional, which means if you do not provide that argument, |
- | // Get' | + | |
- | source.getMinecraftServer(); | + | In this case, we add one integer argument, and calculate |
- | // Access to the instance | + | |
- | source.getName(); | + | <code java> |
- | // The name of the command source. This could be the name of the entity, player, the name of a CommandBlock that has been renamed before being placed down or in the case of the Console, | + | dispatcher.register(literal(" |
- | + | .then(argument("value", IntegerArgumentType.integer()) | |
- | source.hasPermissionLevel(int level); | + | .executes(context -> { |
- | // Returns true if the source of the command has a certain permission level. This is based on the operator status of the sender. (On an integrated server, the player must have cheats enabled to execute these commands) | + | final int value = IntegerArgumentType.getInteger(context, |
+ | final int result = value * value; | ||
+ | context.getSource().sendFeedback(() -> Text.literal(" | ||
+ | return result; | ||
+ | }))); | ||
</ | </ | ||
- | ===== Some actual examples ===== | + | In this case, after the word ''/ |
- | Just a few to show: | + | Note: for simplicity, '' |
- | === Broadcast a message === | + | Then we add an optional second argument: |
- | + | <code java> | |
- | <code java [enable_line_numbers=" | + | dispatcher.register(literal(" |
- | public static void register(CommandDispatcher< | + | .then(argument(" |
- | dispatcher.register(literal(" | + | |
- | .requires(source -> source.hasPermissionLevel(2)) // Must be a game master to use the command. Command will not show up in tab completion or execute to non op's or any op that is permission level 1. | + | final int value = IntegerArgumentType.getInteger(context, |
- | | + | final int result = value * value; |
- | .then(argument(" | + | context.getSource().sendFeedback(() -> Text.literal("%s × %s = %s".formatted(value, value, result)), false); |
- | | + | |
- | } | + | }) |
- | + | | |
- | public static | + | .executes(context |
- | Text text = new LiteralText(message).formatting(formatting); | + | final int value = IntegerArgumentType.getInteger(context, "value"); |
- | + | final int value2 = IntegerArgumentType.getInteger(context, "value2"); | |
- | source.getMinecraftServer().getPlayerManager().broadcastChatMessage(text, false); | + | |
- | return | + | |
- | } | + | return |
+ | })))); | ||
</ | </ | ||
- | === / | + | Now you can type one or two integers. If you give one integer, that integer will be self-multiplied. If you provide two integers, they will be multipled. You may find it unnecessary to specify similar executions twice. Therefore, we can create a method that will be used in both executions. |
- | First the basic code where we register "giveMeDiamond" | + | <code java> |
+ | public class ExampleMod implements ModInitializer { | ||
+ | @Override | ||
+ | public void onInitialize() { | ||
+ | CommandRegistrationCallback.EVENT.register((dispatcher, | ||
+ | .then(argument(" | ||
+ | .executes(context -> executeMultiply(IntegerArgumentType.getInteger(context, | ||
+ | .then(argument(" | ||
+ | .executes(context -> executeMultiply(IntegerArgumentType.getInteger(context, | ||
+ | } | ||
- | <code java [enable_line_numbers=" | + | private |
- | public | + | |
- | | + | context.getSource().sendFeedback(() -> Text.literal("%s × %s = %s" |
- | | + | return result; |
+ | } | ||
} | } | ||
</ | </ | ||
+ | ===== A sub command ===== | ||
- | Then since we only want to give to players, we check if the CommandSource is a player. But we can use '' | + | To add a sub command, you register |
- | < | + | < |
- | public static int giveDiamond(CommandContext< | + | dispatcher.register(literal(" |
- | ServerCommandSource source = ctx.getSource(); | + | |
- | + | ||
- | PlayerEntity self = source.getPlayer(); // If not a player than the command ends | + | |
</ | </ | ||
- | Then we add to the player' | + | In order to have a sub command, one needs to append |
<code java [enable_line_numbers=" | <code java [enable_line_numbers=" | ||
- | if(!player.inventory.insertStack(new ItemStack(Items.DIAMOND))){ | + | dispatcher.register(literal(" |
- | throw new SimpleCommandExceptionType(new TranslateableText("inventory.isfull")).create(); | + | .then(literal("bar") |
- | } | + | |
- | return | + | // For versions below 1.19, use '' |
- | } | + | // For versions below 1.20, use directly the '' |
- | </code> | + | context.getSource().sendFeedback(() -> Text.literal(" |
- | === Antioch === | + | return 1; |
- | ...lobbest thou thy Holy Hand Grenade of Antioch towards thy foe. | + | }) |
- | who being naughty in My sight, shall snuff it. | + | ) |
- | + | ); | |
- | Aside from the joke this command summons a primed TNT to a specified location or the location of the sender' | + | |
- | + | ||
- | First create an entry into the CommandDispatcher that takes a literal of antioch with an optional argument of the location to summon the entity at. | + | |
- | + | ||
- | <code java [enable_line_numbers=" | + | |
- | public static void register(CommandDispatcher< | + | |
- | | + | |
- | | + | |
- | .executes(ctx -> antioch(ctx.getSource(), | + | |
- | .executes(ctx -> antioch(ctx.getSource(), | + | |
- | } | + | |
</ | </ | ||
- | Then the creation | + | Similar to arguments, sub command nodes can also be set optional. In the following cases, both ''/ |
<code java [enable_line_numbers=" | <code java [enable_line_numbers=" | ||
- | public static int antioch(ServerCommandSource source, BlockPos blockPos) throws CommandSyntaxException { | + | dispatcher.register(literal(" |
- | + | .executes(context | |
- | if(blockPos==null) { | + | |
- | blockPos = LocationUtil.calculateCursorOrThrow(source, | + | |
- | } | + | |
- | + | ||
- | TntEntity tnt = new TntEntity(source.getWorld(), | + | |
- | + | ||
- | source.getMinecraftServer().getPlayerManager().broadcastChatMessage(new LiteralText(" | + | |
- | source.getMinecraftServer().getPlayerManager().broadcastChatMessage(new LiteralText(" | + | |
- | source.getWorld().spawnEntity(tnt); | + | |
- | return 1; | + | |
- | } | + | |
- | </ | + | |
- | + | ||
- | === Finding Biomes via Command === | + | |
- | + | ||
- | This example shows examples of redirects, exceptions, suggestions and a tiny bit of text. Note this command when used works but can take a bit of time to work similarly to ''/ | + | |
- | <code java [enable_line_numbers=" | + | |
- | public class CommandLocateBiome { | + | |
- | // First make method to register | + | |
- | public static void register(CommandDispatcher< | + | |
- | LiteralCommandNode< | + | |
- | | + | |
- | .then(argument(" | + | |
- | | + | |
- | .executes(ctx -> execute(ctx.getSource(), | + | |
- | // Register redirect | + | |
- | dispatcher.register(literal(" | + | |
- | .redirect(basenode)); | + | |
- | } | + | |
- | // Beginning of the method | + | |
- | private static int execute(ServerCommandSource source, Identifier biomeId, int range) throws CommandSyntaxException | + | |
- | | + | |
- | + | ||
- | if(biome == null) { // Since the argument is an Identifier we need to check if the identifier actually exists in the registry | + | |
- | throw new SimpleCommandExceptionType(new TranslatableText(" | + | |
- | } | + | |
- | + | ||
- | List< | + | |
- | bio.add(biome); | + | |
- | + | ||
- | ServerWorld world = source.getWorld(); | + | |
- | + | ||
- | BiomeSource bsource = world.getChunkManager().getChunkGenerator().getBiomeSource(); | + | |
- | + | ||
- | BlockPos loc = new BlockPos(source.getPosition()); | + | |
- | // Now here is the heaviest part of the method. | + | |
- | BlockPos pos = bsource.locateBiome(loc.getX(), | + | |
- | + | ||
- | // Since this method can return null if it failed to find a biome | + | |
- | if(pos == null) { | + | |
- | throw new SimpleCommandExceptionType(new TranslatableText(" | + | |
- | } | + | |
- | + | ||
- | int distance = MathHelper.floor(getDistance(loc.getX(), | + | |
- | // Popup text that can suggest commands. This is the exact same system that /locate uses. | + | |
- | Text teleportButtonPopup = Texts.bracketed(new TranslatableText(" | + | |
- | style_1x.setColor(Formatting.GREEN).setClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, | + | |
- | }); | + | |
- | + | ||
- | source.sendFeedback(new TranslatableText(" | + | |
return 1; | return 1; | ||
- | } | + | }) |
- | | + | .then(literal(" |
- | private static float getDistance(int int_1, int int_2, int int_3, int int_4) { | + | .executes(context |
- | int int_5 = int_3 - int_1; | + | |
- | int int_6 = int_4 - int_2; | + | return |
- | + | }) | |
- | return MathHelper.sqrt((float) (int_5 * int_5 + int_6 * int_6)); | + | |
- | } | + | ); |
- | + | ||
- | + | ||
- | + | ||
- | public static class BiomeCompletionProvider { | + | |
- | | + | |
- | public static final SuggestionProvider< | + | |
- | | + | |
- | return | + | |
- | }); | + | |
- | | + | |
- | | + | |
</ | </ | ||
+ | ====== Advanced concepts ====== | ||
- | ===== Custom Arguments (Coming Soon) ===== | + | Below are links to the articles about more complex concepts used in brigadier. |
- | Coming Soon | + | ^ Page ^ Description |
+ | | [[command_exceptions | ||
+ | | [[command_suggestions|Suggestions]] | ||
+ | | [[command_redirects|Redirects]] | ||
+ | | [[command_argument_types|Custom Argument Types]] | ||
+ | | [[command_examples|Examples]] | Some example commands | | ||
- | ===== FAQ ===== | + | ====== FAQ ====== |
- | === What else can I send feedback to the CommandSource? | + | ===== Why does my code not compile ===== |
- | You can choose between Brigadier' | + | There are several immediate possibilities for why this could occur. |
- | === Why does my IDE complain saying that a method executed by my command needs to catch or throw a CommandSyntaxException | + | * **Catch or throw a CommandSyntaxException: |
+ | * **Issues with generics:** You may have an issue with generics once in a while. If you are registering server command (which is most of the case), make sure you are using '' | ||
+ | * **Check '' | ||
+ | * **'' | ||
- | The solution to this is just to make the methods throw a CommandSyntaxException down the whole chain as the executes block handles the exceptions. | + | ===== Can I register client side commands? ===== |
- | === Can I register commands in run time? === | + | Fabric has a '' |
- | + | ||
- | You can do this but it is not reccomended. You would get the instance of the CommandManager and add anything you wish to the CommandDispatcher within it. | + | |
- | + | ||
- | After that you will need to send the command tree to every player again using '' | + | |
- | + | ||
- | === Can I unregister commands in run time? === | + | |
- | + | ||
- | You can also do this but it is very unstable and could cause unwanted side effects. Lets just say it involves a bunch of Reflection. | + | |
- | + | ||
- | Once again you will need to send the command tree to every player again using '' | + | |
- | + | ||
- | === Can I register client side commands? === | + | |
- | + | ||
- | Well Fabric currently doesn' | + | |
- | https:// | + | |
- | + | ||
- | If you only want the command to only be visible on the integrated server like ''/ | + | |
<code java> | <code java> | ||
- | dispatcher.register(literal(" | + | ClientCommandRegistrationCallback.EVENT.register((dispatcher, |
- | // The permission level 4 on integrated server is the equivalent of having cheats enabled. | + | .executes(context |
- | .requires(source | + | context.getSource().sendFeedback(Text.literal("The command is executed in the client!" |
+ | return 1; | ||
+ | } | ||
+ | | ||
</ | </ | ||
- | === I want to access X from my mod when a command | + | If you need to open a screen in the client |
- | This is going to require a way to statically access your mod with a '' | + | ===== Can I register commands |
- | <code java> | + | You can do this but it is not recommended. You would get the '' |
- | private static Type instance; | + | |
- | static { // Static option on class initalize for seperate API class for example | + | After that you need to send the command tree to every player again using '' |
- | | + | |
- | } | + | |
- | public void onInitalize() { // If within your mod initalizer | + | ===== Can I unregister commands in runtime? ===== |
- | | + | |
- | } | + | You can also do this, however it is much less stable than registering commands and could cause unwanted side effects. To keep things simple, you need to use reflection on brigadier and remove the nodes. After this, you need to send the command tree to every player again using '' |
- | public static Type getInstance() { | ||
- | return instance; | ||
- | } | ||
- | </ |
tutorial/commands.txt · Last modified: 2024/02/23 14:22 by allen1210