tutorial:commands
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
tutorial:commands [2019/08/22 03:55] – [A very basic command] Change ArgumentBuilders to CommandManager i509vcb | tutorial:commands [2024/02/23 14:22] (current) – Documenting and first draft allen1210 | ||
---|---|---|---|
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 | + | ===== What is Brigadier? |
- | If you just want to see how to register | + | Brigadier is a command parser & dispatcher written by Mojang for use in Minecraft. Brigadier is a tree based command library where you build a tree of arguments and commands. |
- | Registering commands is done through '' | + | The source code for brigadier can be found here: https:// |
- | The '' | + | ===== The '' |
- | The dedicated flag if set to true will tell Fabric to only register the command on a '' | + | In Minecraft, '' |
- | Below are a few examples | + | The single method in '' |
- | <code java [enable_line_numbers=" | + | Like other functional interfaces, it is usually used as a lambda or a method reference: |
- | CommandRegistry.INSTANCE.register(false, | + | |
- | + | <code java> | |
- | CommandRegistry.INSTANCE.register(false, | + | Command< |
- | | + | |
- | TutorialHelpCommand.register(dispatcher); | + | }; |
- | }); | + | |
- | + | ||
- | CommandRegistry.INSTANCE.register(true, | + | |
- | dispatcher.register(LiteralArgumentBuilder.literal(" | + | |
- | }); | + | |
</ | </ | ||
- | ==== A very basic command | + | 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 '' |
+ | |||
+ | |||
+ | ==== What can the ServerCommandSource do? ==== | ||
- | Wait isn't this the exact same command | + | A '' |
<code java [enable_line_numbers=" | <code java [enable_line_numbers=" | ||
- | // The root of the command. This must be a literal argument. | + | // Get the source. This will always work. |
- | dispatcher.register(CommandManager.literal(" | + | final ServerCommandSource source = ctx.getSource(); |
- | // 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("Bar is " + IntArgumentType.getInteger(ctx, | + | |
- | // Return a result. -1 is failure, 0 is a pass and 1 is success. | + | |
- | return 1; | + | |
- | })) | + | |
- | // The command " | + | |
- | .executes(ctx -> { | + | |
- | System.out.println(" | + | |
- | return 1; | + | |
- | }) | + | |
- | ); | + | |
- | </ | + | |
- | The main process registers | + | // Unchecked, may be null if the sender |
- | Since the root node must be literal, The sender | + | final @Nullable Entity sender = source.getEntity(); |
- | ===== Brigadier Explained ===== | + | // Will throw an exception if the executor 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. | ||
+ | final @NotNull Entity sender2 | ||
- | Brigadier starts with the '' | + | // null if the executor |
- | The trunk of the tree is the CommandDispatcher. | + | final @Nullable ServerPlayerEntity player = source.getPlayer(): |
- | 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 | + | // Will throw an exception if the executor of the command |
+ | // Also will send feedback telling the sender of the command that they must be a player. | ||
+ | // This method will require your methods | ||
+ | final @NotNull ServerPlayerEntity player = source.getPlayerOrThrow(); | ||
- | ==== CommandContexts ==== | + | // Gets the sender' |
+ | // This could be the location of the entity/ | ||
+ | final Vec3d position | ||
- | When a command is ran, Brigadier provides a CommandContext to the command that is ran. | + | // Gets the world the sender |
- | The CommandContext contains all arguments and other objects such as the inputted String and the '' | + | final ServerWorld world = source.getWorld(); |
- | ==== Arguments ==== | + | // Gets the sender' |
+ | final Vec2f rotation | ||
- | The arguments in Brigadier both parse and error check any inputted arguments. | + | // Access to the instance of the MinecraftServer this command was ran on. |
- | Minecraft creates some special arguments for it's own use such as the '' | + | final MinecraftServer server |
- | You could do the long method | + | // The name of the command source. This could be the name of the entity, player, |
- | This also works for getting arguments, which shortens | + | // the name of a CommandBlock |
- | This also works for Minecraft' | + | final String name = source.getName(); |
- | And your imports would look something like this: | + | // Returns |
- | <code java [enable_line_numbers=" | + | // This is based on the operator status of the sender. |
- | import static com.mojang.brigadier.arguments.StringArgumentType.getString; | + | // (On an integrated server, the player must have cheats enabled to execute these commands.) |
- | import static com.mojang.brigadier.arguments.StringArgumentType.word; | + | final boolean b = source.hasPermissionLevel(int level); |
- | 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' | + | ===== Register a basic command ===== |
- | Minecraft' | + | Commands are registered by registering |
- | ==== Suggestions ==== | + | The event should be registered in your mod's initializer. The callback has three parameters. The '' |
- | Suggestions can be provided to the client | + | To simplify |
- | < | + | < |
- | SUMMONABLE_ENTITIES | + | import static net.minecraft.server.command.CommandManager.*; |
- | AVAILIBLE_SOUNDS | + | |
- | ALL_RECIPES | + | |
- | ASK_SERVER | + | |
</ | </ | ||
- | Loot tables specify their own SuggestionProvider inside LootCommand for example. | + | In the mod initializer, |
- | The example below is a dynamically changing SuggestionProvider that lists several words for a StringArgumentType to demonstrate how it works: | ||
<code java [enable_line_numbers=" | <code java [enable_line_numbers=" | ||
- | public | + | public |
- | | + | @Override |
- | } | + | public void onInitialize() { |
- | + | | |
- | private static CompletableFuture< | + | |
- | | + | // For versions below 1.19, replace "Text.literal" |
- | + | // For versions below 1.20, remode "() ->" directly. | |
- | if(list.isEmpty()) { // If the list is empty then return no suggestions | + | |
- | return Suggestions.empty(); // No suggestions | + | |
- | } | + | return 1; |
- | + | }))); | |
- | for (String str : list) { // Iterate through the supplied list | + | } |
- | if (str.toLowerCase(Locale.ROOT).startsWith(remaining)) { | + | |
- | | + | |
- | } | + | |
- | } | + | |
- | return builder.buildFuture(); // Create the CompletableFuture containing all the suggestions | + | |
} | } | ||
</ | </ | ||
- | The SuggestionProvider | + | **Please ensure you import the correct static method.** |
- | Though remember these are suggestions. The inputted command may not contain an argument you suggested | + | In the '' |
- | To use the suggestion | + | If the command fails, instead of calling '' |
- | <code java [enable_line_numbers=" | + | To execute this command, you must type ''/ |
- | argument(argumentName, word()) | + | |
- | .suggests(CompletionProviders.suggestedStrings()) | + | |
- | .then(/*Rest of the command*/)); | + | |
- | </code> | + | |
- | ==== Requires | + | ===== Registration environment |
+ | If desired, you can also make sure a command is only registered under some specific circumstances, | ||
- | Lets say you have a command you only want operators to be able to execute. This is where the '' | + | < |
+ | public class ExampleCommandMod implements ModInitializer { | ||
+ | @Override | ||
+ | public void onInitialize() { | ||
+ | CommandRegistrationCallback.EVENT.register((dispatcher, | ||
+ | | ||
+ | ...; | ||
+ | } | ||
+ | }); | ||
+ | } | ||
+ | } | ||
+ | </ | ||
- | For example this may look like the following: | + | ===== Static Imports ===== |
+ | In the example | ||
+ | Below is an example of some static imports: | ||
<code java [enable_line_numbers=" | <code java [enable_line_numbers=" | ||
- | dispatcher.register(literal("foo") | + | // getString(ctx, "string") |
- | .requires(source -> source.hasPermissionLevel(4)) | + | import static com.mojang.brigadier.arguments.StringArgumentType.getString; |
- | .executes(ctx -> { | + | // word() |
- | ctx.getSource().sendFeedback(new LiteralText("You are an operator", | + | import static com.mojang.brigadier.arguments.StringArgumentType.word; |
- | return 1; | + | // literal(" |
- | }); | + | import static net.minecraft.server.command.CommandManager.literal; |
+ | // argument("bar", | ||
+ | import static net.minecraft.server.command.CommandManager.argument; | ||
+ | // Import everything in the CommandManager | ||
+ | import static net.minecraft.server.command.CommandManager.*; | ||
</ | </ | ||
- | This command will only execute if the Source | + | Note: Please be sure you use the '' |
- | ==== Exceptions ==== | + | Brigadier' |
- | Brigadier supports | + | Minecraft' |
- | 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 '' | + | ===== Add Requirements ===== |
- | Below is a coin flip command to show an example of exceptions in use. | + | |
- | <code java [enable_line_numbers=" | + | Let's say you have a command that you only want operators to be able to execute. This is where the '' |
- | dispatcher.register(CommandManager.literal(" | + | |
- | .executes(ctx -> { | + | |
- | Random random = new Random(); | + | |
- | + | ||
- | if(random.nextBoolean()) { // If heads succeed. | + | |
- | ctx.getSource().sendMessage(new TranslateableText(" | + | |
- | return Command.SINGLE_SUCCESS; | + | |
- | } | + | |
- | throw new SimpleCommandExceptionType(new TranslateableText(" | + | |
- | })); | + | |
- | </ | + | |
- | Though you are not just limited to a single type of exception as Brigadier also supplies Dynamic exceptions. | + | For example this may look like the following: |
<code java [enable_line_numbers=" | <code java [enable_line_numbers=" | ||
- | DynamicCommandExceptionType used_name = new DynamicCommandExceptionType(name -> { | + | dispatcher.register(literal(" |
- | return new LiteralText("The name: " + (String) name + " | + | .requires(source -> source.hasPermissionLevel(2)) |
- | }); | + | .executes(ctx |
+ | | ||
+ | return 1; | ||
+ | }); | ||
</ | </ | ||
- | There are more Dynamic exception types which each take a different amount | + | This command will only execute if the source |
- | You should remember that the Dynamic exceptions takes an object as an argument so you may have to cast the argument for your use. | + | |
- | ==== Redirects | + | To create commands that only level 4 operators |
- | Redirects are Brigadier' | + | ===== Arguments ===== |
- | <code java [enable_line_numbers=" | + | Arguments are used in most of commands. Sometimes they can be optional, which means if you do not provide that argument, the command |
- | public static void register(CommandDispatcher< | + | |
- | LiteralCommandNode node = registerMain(dispatcher); | + | |
- | dispatcher.register(literal(" | + | |
- | .redirect(node)); | + | |
- | dispatcher.register(literal(" | + | |
- | .redirect(node)); // Alias 2, redirect to main command | + | |
- | } | + | |
- | public static LiteralCommandNode registerMain(CommandDispatcher< | + | In this case, we add one integer |
- | return dispatcher.register(literal(" | + | |
- | .then(argument(" | + | |
- | .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. | + | <code java> |
- | + | | |
- | Redirects do not work in shortened aliases such as ''/ | + | .then(argument(" |
- | + | .executes(context -> { | |
- | ===== ServerCommandSource ===== | + | final int value = IntegerArgumentType.getInteger(context, " |
- | + | final int result | |
- | What if you wanted a command that the CommandSource must be an entity to execute? The ServerCommandSource provides this option with a couple of methods | + | context.getSource().sendFeedback(() -> Text.literal(" |
- | + | | |
- | <code java [enable_line_numbers=" | + | }))); |
- | ServerCommandSource source = ctx.getSource(); | + | |
- | // Get the source. This will always work. | + | |
- | + | ||
- | Entity sender = source.getEntity(); | + | |
- | // Unchecked, may be null if the sender was the console. | + | |
- | + | ||
- | Entity sender2 | + | |
- | // Will end the command if the source of the command was not an Entity. | + | |
- | // The result | + | |
- | // 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 | + | |
- | // Will end the command if the source of the command was not explicitly a Player. Also will send feedback telling the sender of the command that they must be a player. | + | |
</ | </ | ||
- | The ServerCommandSource also provides other information about the sender of the command. | + | In this case, after the word ''/ |
- | <code java [enable_line_numbers=" | + | Note: for simplicity, '' |
- | source.getPosition(); | + | |
- | // Get's the sender's position as a Vec3 when the command was sent. This could be the location of the entity/ | + | |
- | source.getWorld(); | + | Then we add an optional second argument: |
- | // Get's the world the sender is within. The console' | + | <code java> |
- | + | dispatcher.register(literal(" | |
- | source.getRotation(); | + | .then(argument(" |
- | // Get's the sender' | + | |
- | + | final int value = IntegerArgumentType.getInteger(context, " | |
- | source.getMinecraftServer(); | + | final int result = value * value; |
- | // Access to the instance of the MinecraftServer this command was ran on. | + | context.getSource().sendFeedback(() -> Text.literal(" |
- | + | | |
- | source.getName(); | + | }) |
- | // 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, "Console" | + | |
- | + | .executes(context -> { | |
- | source.hasPermissionLevel(int level); | + | final int value = IntegerArgumentType.getInteger(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 value2 = IntegerArgumentType.getInteger(context, "value2"); |
+ | final int result = value * value2; | ||
+ | | ||
+ | return result; | ||
+ | })))); | ||
</ | </ | ||
- | ===== Some actual examples ===== | + | Now you can type one or two integers. If you give one integer, that square of integer will be calculated. If you provide two integers, their product will be calculated. You may find it unnecessary to specify similar executions twice. Therefore, we can create a method that will be used in both executions. |
- | Just a few to show: | + | <code java> |
- | + | public class ExampleMod implements ModInitializer { | |
- | === Broadcast a message === | + | |
+ | 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 | + | |
- | | + | |
- | .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. | + | return result; |
- | .then(argument(" | + | } |
- | .then(argument("message", greedyString()) | + | |
- | | + | |
} | } | ||
+ | </ | ||
+ | ===== A sub command ===== | ||
- | public static int broadcast(ServerCommandSource source, Formatting formatting, String message) { | + | To add a sub command, you register the first literal node of the command normally. |
- | Text text = new LiteralText(message).formatting(formatting); | + | |
- | source.getMinecraftServer().getPlayerManager().broadcastChatMessage(text, | + | < |
- | return Command.SINGLE_SUCCESS; | + | dispatcher.register(literal(" |
- | } | + | |
</ | </ | ||
- | === / | + | In order to have a sub command, one needs to append the next node to the existing node. |
- | First the basic code where we register " | + | This creates |
<code java [enable_line_numbers=" | <code java [enable_line_numbers=" | ||
- | public static LiteralCommandNode | + | dispatcher.register(literal(" |
- | | + | .then(literal(" |
- | .executes(ctx -> giveDiamond(ctx))); | + | .executes(context |
- | } | + | // For versions below 1.19, use '' |
- | </ | + | // For versions below 1.20, use directly the '' |
+ | context.getSource().sendFeedback(() -> Text.literal(" | ||
- | Then since we only want to give to players, we check if the CommandSource is a player. But we can use '' | + | return 1; |
- | + | }) | |
- | <code java [enable_line_numbers=" | + | ) |
- | public static int giveDiamond(CommandContext< | + | ); |
- | | + | |
- | + | ||
- | PlayerEntity self = source.getPlayer(); // If not a player than the command ends | + | |
</ | </ | ||
- | Then we add to the player' | + | Similar |
<code java [enable_line_numbers=" | <code java [enable_line_numbers=" | ||
- | if(!player.inventory.insertStack(new ItemStack(Items.DIAMOND))){ | + | dispatcher.register(literal(" |
- | | + | |
- | } | + | context.getSource().sendFeedback(() -> Text.literal(" |
- | | + | |
- | } | + | }) |
+ | .then(literal("bar") | ||
+ | .executes(context -> { | ||
+ | context.getSource().sendFeedback(() -> Text.literal(" | ||
+ | return 1; | ||
+ | }) | ||
+ | ) | ||
+ | ); | ||
</ | </ | ||
+ | ====== Advanced concepts ====== | ||
- | === Antioch === | + | Below are links to the articles about more complex concepts used in brigadier. |
- | ...lobbest thou thy Holy Hand Grenade of Antioch towards thy foe. | + | |
- | who being naughty | + | |
- | Aside from the joke this command | + | ^ Page ^ Description |
+ | | [[command_exceptions | ||
+ | | [[command_suggestions|Suggestions]] | ||
+ | | [[command_redirects|Redirects]] | ||
+ | | [[command_argument_types|Custom Argument Types]] | ||
+ | | [[command_examples|Examples]] | Some example commands | | ||
- | 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. | + | ====== FAQ ====== |
- | <code java [enable_line_numbers=" | + | ===== Why does my code not compile ===== |
- | public static void register(CommandDispatcher< | + | |
- | dispatcher.register(literal(" | + | |
- | .then(required(" | + | |
- | .executes(ctx -> antioch(ctx.getSource(), | + | |
- | .executes(ctx -> antioch(ctx.getSource(), | + | |
- | } | + | |
- | </code> | + | |
- | Then the creation and messages behind the joke. | + | There are several immediate possibilities for why this could occur. |
- | <code java [enable_line_numbers=" | + | * **Catch or throw a CommandSyntaxException: |
- | public static int antioch(ServerCommandSource source, BlockPos blockPos) | + | * **Issues with generics:** You may have an issue with generics once in a while. If you are registering server command |
- | + | * **Check '' | |
- | if(blockPos==null) { | + | * **'' |
- | blockPos = LocationUtil.calculateCursorOrThrow(source, source.getRotation()); | + | |
- | } | + | |
- | + | ||
- | TntEntity tnt = new TntEntity(source.getWorld(), blockPos.getX(), blockPos.getY(), blockPos.getZ(), null); | + | |
- | + | ||
- | source.getMinecraftServer().getPlayerManager().broadcastChatMessage(new LiteralText(" | + | |
- | source.getMinecraftServer().getPlayerManager().broadcastChatMessage(new LiteralText(" | + | |
- | source.getWorld().spawnEntity(tnt); | + | |
- | return | + | |
- | } | + | |
- | </ | + | |
- | === Finding Biomes via Command | + | ===== Can I register client side commands? ===== |
- | 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 '' | + | Fabric has a '' |
- | <code java [enable_line_numbers=" | + | |
- | public class CommandLocateBiome { | + | |
- | // First make method | + | |
- | public static void register(CommandDispatcher< | + | |
- | LiteralCommandNode< | + | |
- | .then(argument(" | + | |
- | .then(argument(" | + | |
- | .executes(ctx -> execute(ctx.getSource(), | + | |
- | .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 { | + | |
- | Biome biome = Registry.BIOME.get(biomeId); | + | |
- | + | ||
- | if(biome == null) { // Since the argument is an Identifier we need to check if the identifier actually exists | + | |
- | 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; | + | <code java> |
- | | + | |
- | // Just a normal old 2d distance method. | + | .executes(context |
- | private static float getDistance(int int_1, int int_2, int int_3, int int_4) { | + | |
- | int int_5 = int_3 - int_1; | + | return |
- | int int_6 = int_4 - int_2; | + | } |
- | + | | |
- | return MathHelper.sqrt((float) (int_5 * int_5 + int_6 * int_6)); | + | |
- | } | + | |
- | + | ||
- | + | ||
- | + | ||
- | public static class BiomeCompletionProvider { | + | |
- | // This provides suggestions of what biomes can be selected. Since this uses the registry, mods that add new biomes will work without modification. | + | |
- | public static final SuggestionProvider< | + | |
- | | + | |
- | return | + | |
- | | + | |
- | + | ||
- | } | + | |
</ | </ | ||
- | ===== FAQ ===== | + | If you need to open a screen in the client command execution, instead of directly calling '' |
- | === What else can I send feedback to the CommandSource? === | + | ===== Can I register commands in runtime? ===== |
- | You can choose between Brigadier's default LiteralMessage or use any one of Minecraft' | + | You can do this but it is not recommended. You would get the '' |
- | === Why does my IDE complain saying | + | After that you need to send the command |
- | 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 unregister commands in runtime? ===== |
- | === Can I register | + | You can also do this, however it is much less stable than registering |
- | You can do this but it is not reccomended. You would get the instance of the CommandManager | + | ===== Can I execute command without typing in game? ===== |
+ | Yes! You can. Before trying | ||
- | After that you will need to send the command tree to every player again using '' | + | Here is the code example |
- | + | ||
- | === 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(" | + | private void vanillaCommandByPlayer(World world, BlockPos pos, String command) { |
- | // The permission level 4 on integrated server is the equivalent of having cheats enabled. | + | PlayerEntity player = world.getClosestPlayer(pos.getX(), pos.getY(), pos.getZ(), 5, false); |
- | .requires(source -> source.getMinecraftServer().isSinglePlayer() && source.hasPermissionLevel(4))); | + | if (player != null) { |
+ | CommandManager commandManager = Objects.requireNonNull(player.getServer()).getCommandManager(); | ||
+ | ServerCommandSource commandSource = player.getServer().getCommandSource(); | ||
+ | commandManager.executeWithPrefix(commandSource, | ||
+ | } | ||
+ | } | ||
</ | </ | ||
- | === I want to access X from my mod when a command is ran === | + | First, you need a CommandManager< |
+ | Second, you need the ServerCommandSource. | ||
+ | Then, u can call some CommandManager public methods like commandeManader.execute. (.execute need ParseResults< | ||
+ | But commandeManader.executeWithPrefix allow you to use String. You can also put the slash (/). | ||
- | This is going to require a way to statically access your mod with a '' | + | So... have fun! |
- | + | ||
- | <code java> | + | |
- | private static Type instance; | + | |
- | + | ||
- | static { // Static option on class initalize for seperate API class for example | + | |
- | | + | |
- | } | + | |
- | + | ||
- | public void onInitalize() { // If within your mod initalizer | + | |
- | | + | |
- | } | + | |
- | + | ||
- | public static Type getInstance() { | + | |
- | return instance; | + | |
- | } | + | |
- | </ | + |
tutorial/commands.txt · Last modified: 2024/02/23 14:22 by allen1210