User Tools

Site Tools


tutorial:commands

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
Next revisionBoth sides next revision
tutorial:commands [2020/06/14 01:12] – Reword static imports section i509vcbtutorial:commands [2020/06/14 05:17] – Move old categories below FAQ to be migrated i509vcb
Line 1: Line 1:
 ====== Creating Commands ====== ====== Creating Commands ======
  
-Creating commands can allow a mod developer to add functionality that a player can use through a command.  +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 command structure of Brigadier.+This tutorial will teach you how to register commands, and the general command structure of Brigadier.
  
 Note: All code written here was written for 1.14.4. Some mappings may have changed in yarn, but all code should still be applicable. Note: All code written here was written for 1.14.4. Some mappings may have changed in yarn, but all code should still be applicable.
  
-===== Registering Commands =====+===== What is Brigadier? =====
  
-Registering commands is done by registering new listener in the ''CommandRegistrationCallback''. +Brigadier is a command parser & dispatcher written by Mojang for use in MinecraftBrigadier is a tree based command library where you build a tree of arguments and commands.
-The event should be registered in your mod's initializer.+
  
-The dedicated parameter if true will tell event listeners that the server commands are being registered on is a ''dedicated server''. If false than the commands will registered on an ''integrated server''+The source code for brigadier can be found here: https://github.com/Mojang/brigadier
-Below are a few examples of how the commands can be registered.+
  
 +===== What is a command? =====
 +
 +Brigadier requires you specify the ''Command'' to be run. A "command" is a fairly loose term within brigadier, but typically it means an exit point of the command tree. This is where the code is executed for your command.
 +A ''Command'' is a functional interface. The command has a generic type of ''S'' which defines the type of the command source. The command source provides some context in which a command was ran. In Minecraft, this is typically a ''ServerCommandSource'' which can represent a server, a command block, rcon connection, a player or an entity.
 +
 +The single method in ''Command'', ''run(CommandContext<S>)'' takes a ''CommandContext<S>'' as the sole parameter and returns an integer. The command context holds your command source of ''S'' and allows you to obtain arguments, look at the parsed command nodes and see the input used in this command.
 +
 +A command can be implemented in several ways as shown below:
 +
 +**__As a lambda__**
 <code java [enable_line_numbers="true"]> <code java [enable_line_numbers="true"]>
-// Method reference +Command<Object> command = context -> { 
-CommandRegistrationCallback.EVENT.register(TutorialCommands::register);+    return 0; 
 +}; 
 +</code>
  
-// Using a lambda +**__As an anonymous class__** 
-CommandRegistrationCallback.EVENT.register((dispatcher, dedicated) -{ +<code java [enable_line_numbers="true"]
-    // This command will be registered regardless of the server being dedicated or integrated +Command<Object> command = new Command<Object>() { 
-    TutorialCommand.register(dispatcher); +    @Override 
-    if (dedicated) { +    public int run(CommandContext<Object> context) { 
-        // This command will only be registered on a dedicated server +        return 0;
-        TutorialHelpCommand.register(dispatcher)+
-    } else +
-        // This command will only be registered on an integrated server. +
-        // Commands which call client only classes and methods should be registered in your ClientModInitializer +
-        IntegratedTutorialHelpCommand.register(dispatcher)+
     }     }
-});+} 
 +</code>
  
-// Or register directly +**__Implemented as a class__** 
-CommandRegistrationCallback.EVENT.register((dispatcher, dedicated) -> { +<code java [enable_line_numbers="true"]> 
-    dispatcher.register(LiteralArgumentBuilder.literal("tutorial").executes(ctx -execute(ctx))); +final class XYZCommand implements Command<Object> { 
-});+    @Override 
 +    public int run(CommandContext<Objectcontext
 +        return 0; 
 +    } 
 +}
 </code> </code>
  
-==== A very basic command ====+**__As a method reference__** 
 +<code java [enable_line_numbers="true"]> 
 +void registerCommand() { 
 +    // Ignore this for now, we will explain it next. 
 +    dispatcher.register(CommandManager.literal("foo")) 
 +        .executes(this::execute); // This refers to the "execute" method below. 
 +}
  
-Wait isn'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.+private int execute(CommandContext<Object> context) { 
 +    return 0; 
 +
 +</code> 
 + 
 + 
 +The ''run(CommandContext)'' method can throw a ''CommandSyntaxException'', but this is covered later in the tutorial.  
 + 
 +The integer can be considered the result of the command. In Minecraft, the result can correspond to the power of a redstone comparator feeding from a command block or the value that will be passed the chain command block the command block is facingTypically negative values mean a command has failed and will do nothing. A result of ''0'' means the command has passed. Positive values mean the command was successful and did something. 
 + 
 +===== A basic command ===== 
 + 
 +Below is a command that contains no arguments:
  
 <code java [enable_line_numbers="true"]> <code java [enable_line_numbers="true"]>
-// The root of the command. This must be a literal argument+dispatcher.register(CommandManager.literal("foo").executes(context -> {  
-dispatcher.register(CommandManager.literal("foo")  +    System.out.println("Called foo with no arguments"); 
-// Then add an argument named bar that is an integer + 
-    .then(CommandManager.argument("bar", integer()) +    return 1; 
-        // The command to be executed if the command "foo" is entered with the argument "bar" +})); 
-        .executes(ctx -> {  +</code> 
-            System.out.println("Bar is " + IntArgumentType.getInteger(ctx, "bar")); + 
-            // Return a result. Typically -1 is failure, 0 is pass and 1 is success.+''CommandManager.literal("foo")'' tells brigadier this command has one node, a **literal** called ''foo''
 +To execute this command, one must type ''/foo''. If ''/Foo'', ''/FoO'', ''/FOO'', ''/fOO'' or ''/fooo'' is typed instead, the command will not run. 
 + 
 +==== A sub command ==== 
 + 
 +To add sub command, you register the first literal node of the command normally. 
 + 
 +<code java [enable_line_numbers="true"]> 
 +dispatcher.register(CommandManager.literal("foo"
 +</code> 
 + 
 +In order to have a sub command, one needs to append the next node to the existing node. This is done use the ''then(ArgumentBuilder)'' method which takes in an ''ArgumentBuilder''
 + 
 +This creates the command ''foo <bar>'' as shown below. 
 + 
 +<code java [enable_line_numbers="true", highlight_lines_extra="2"]> 
 +dispatcher.register(CommandManager.literal("foo") 
 +    .then(CommandManager.literal("bar")) 
 +); 
 +</code> 
 + 
 +It is advised to indent your code as you add nodes to the command. Usually the indentation corresponds to how many nodes deep one is on the command tree. The new line also makes it visible that another node is being added. There are alternative styles to formatting the tree command that are shown later on in this tutorial. 
 + 
 +**So let's try running the command** 
 + 
 +Most likely if you typed ''/foo bar'' in game, the command will fail to run. This is because there is no code for the game to execute when all the required arguments have been met. To fix this, you need to tell the game what to run when the command is being executed using the ''executes(Command)'' method. Below is how the command should look as an example. 
 + 
 +<code java [enable_line_numbers="true", highlight_lines_extra="3,4,5,6,7"]> 
 +dispatcher.register(CommandManager.literal("foo"
 +    .then(CommandManager.literal("bar") 
 +        .executes(context -> { 
 +            System.out.println("Called foo with bar"); 
             return 1;             return 1;
-        })+        }) 
-    // The command "foo" to execute if there are no arguments. +    )
-    .executes(ctx -> {  +
-        System.out.println("Called foo with no arguments"); +
-        return 1; +
-    })+
 ); );
 </code> </code>
  
-The main process registers the command ''foo'' (Root Node) with an optional argument of ''bar'' (Child node).  +===== Registering the commands =====
-Since the root node must be literal, The sender must enter the exact same sequence of letters to execute the command, so ''Foo'', ''fOo'' or ''fooo'' will not execute the command.+
  
-===== Brigadier Explained =====+Registering commands is done by registering a callback using the ''CommandRegistrationCallback''. For information on registering callbacks, please see the [[tutorial:callbacks|callbacks article]].
  
-Brigadier starts with the ''CommandDispatcher'' which should be thought more as a tree of command nodes.+The event should be registered in your mod's initializer. The callback has two parameters. The ''CommmandDispatcher<S>'' is used to register, parse and execute commands. ''S'' is the type of command source the command dispatcher supports. The second parameter is a boolean which identifies the type of server the commands are being registered. on is an ''dedicated'' or ''integrated'' (false) server.
  
-Command nodes are similar to the branches that define the command tree. The executes blocks can be seen at the leaves of the tree where a branch ends and also supplies the command to be executed. 
  
-The execute blocks specify the command to be ranAs Brigadier's Command is a functional interface you can use lambdas to specify commands.+<code java [enable_line_numbers="true"]> 
 +public class ExampleCommandMod implements ModInitializer { 
 +    @Override 
 +    public void onInitialize() { 
 +        CommandRegistrationCallback.EVENT.register((dispatcher, dedicated) -> { 
 +            ... 
 +        }); 
 +    } 
 +
 +</code>
  
-==== CommandContexts ====+Inside your lambda, method reference or whatever you have chosen, you will register your commands.
  
-When a command is ranBrigadier provides a ''CommandContext'' to the command that is ran.  +<code java [enable_line_numbers="true"highlight_lines_extra="5,6,7,8"]> 
-The CommandContext contains all arguments and other objects such as the inputted String and the ''Command Source'' (ServerCommandSource in Minecraft's implementation).+public class ExampleCommandMod implements ModInitializer { 
 +    @Override 
 +    public void onInitialize() { 
 +        CommandRegistrationCallback.EVENT.register((dispatcher, dedicated) -> { 
 +            dispatcher.register(CommandManager.literal("foo").executes(context -> { 
 +                System.out.println("foo"); 
 +                return 1; 
 +            })); 
 +        }); 
 +    } 
 +
 +</code>
  
-==== Arguments ====+If desired, you can make sure a command is only registered on a dedicated server by checking the ''dedicated'' flag 
 + 
 + 
 +<code java [enable_line_numbers="true", highlight_lines_extra="5,6,7"]> 
 +public class ExampleCommandMod implements ModInitializer { 
 +    @Override 
 +    public void onInitialize() { 
 +        CommandRegistrationCallback.EVENT.register((dispatcher, dedicated) -> { 
 +            if (dispatcher) { 
 +                TestDedicatedCommand.register(dispatcher); 
 +            } 
 +        }); 
 +    } 
 +
 +</code> 
 + 
 +And vice versa 
 + 
 +<code java [enable_line_numbers="true", highlight_lines_extra="5,6,7"]> 
 +public class ExampleCommandMod implements ModInitializer { 
 +    @Override 
 +    public void onInitialize() { 
 +        CommandRegistrationCallback.EVENT.register((dispatcher, dedicated) -> { 
 +            if (!dispatcher) { 
 +                TestIntegratedCommand.register(dispatcher); 
 +            } 
 +        }); 
 +    } 
 +
 +</code> 
 + 
 +===== Arguments =====
  
 Arguments in Brigadier both parse and error check any inputted arguments. Arguments in Brigadier both parse and error check any inputted arguments.
 Minecraft creates some special argument types for it's own use such as the ''EntityArgumentType'' which represents the in-game entity selectors ''@a, @r, @p, @e[type=!player, limit=1, distance=..2]'', or an ''NbtTagArgumentType'' that parses stringified nbt (snbt) and verifies that the input is the correct syntax. Minecraft creates some special argument types for it's own use such as the ''EntityArgumentType'' which represents the in-game entity selectors ''@a, @r, @p, @e[type=!player, limit=1, distance=..2]'', or an ''NbtTagArgumentType'' that parses stringified nbt (snbt) and verifies that the input is the correct syntax.
  
-==== Static Imports ====+**TODO:** Go into more detail on how to use arguments 
 + 
 +===== Static Imports =====
 You could type out ''CommandManager.literal("foo")'' every time you want to create a literal. This works, but you can statically import the arguments and shorten the statement to ''literal("foo")''. This also works for getting the value of an argument. This shortens ''StringArgumentType.getString(ctx, "string")'' to ''getString(ctx, "string")''. You could type out ''CommandManager.literal("foo")'' every time you want to create a literal. This works, but you can statically import the arguments and shorten the statement to ''literal("foo")''. This also works for getting the value of an argument. This shortens ''StringArgumentType.getString(ctx, "string")'' to ''getString(ctx, "string")''.
 This also works for Minecraft's own argument types. This also works for Minecraft's own argument types.
Line 107: Line 214:
 CommandManager is in ''net.minecraft.server.command'' CommandManager is in ''net.minecraft.server.command''
  
-==== Suggestions ====+====== Advanced concepts ======
  
-Suggestions can be provided to the client to recommend what to input into the command.  This is used for Scoreboards and Loot Tables ingame. The game stores these in the SuggestionProvidersA few examples of Minecraft's built in suggestions providers are below +Below are links to the articles about more complex concepts used in brigadier.
-<code> +
-SUMMONABLE_ENTITIES +
-AVAILIBLE_SOUNDS +
-ALL_RECIPES +
-ASK_SERVER +
-</code>+
  
-Loot tables specify their own SuggestionProvider inside ''LootCommand'' for example.+^ Page                                                           ^ Description                                                                     ^ 
 +| [[tutorials:commands:requirements|Requirements]]               | Only allow users to execute commands in certain scenarios.                      | 
 +| [[tutorials:commands:exceptions  |Exceptions]]                 | Fail execution of a command with a descriptive message and in certain contexts. |                                                                   
 +| [[tutorials:commands:suggestions |Suggestions]]                | Suggesting input to be sent to the client.                                      | 
 +| [[tutorials:commands:redirects_aliases|Redirects (Aliases)]]   | Allow use of aliases to execute commands.                                       | 
 +| [[tutorials:commands:redirects_chaining|Redirects (Chaining)]] | Allow commands to have repeating elements and flags.                            | 
 +| [[tutorials:commands:argument_types|Custom Argument Types]]    | Parse your own arguments and return your own types                            |
  
-The example below is a dynamically changing SuggestionProvider that lists several words for a StringArgumentType to demonstrate how it works: +**TODO:** Sections are being moved to sub categories and will be added to their respective articles as they are migrated.
-<code java [enable_line_numbers="true"]> +
-public static SuggestionProvider<ServerCommandSource> suggestedStrings() { +
-    return (ctx, builder) -> getSuggestionsBuilder(builder, /*Access to a list here*/); +
-+
-     +
-private static CompletableFuture<Suggestions> getSuggestionsBuilder(SuggestionsBuilder builder, List<String> list) { +
-    String remaining = builder.getRemaining().toLowerCase(Locale.ROOT); +
-         +
-    if(list.isEmpty()) { // If the list is empty then return no suggestions +
-        return Suggestions.empty(); // No suggestions +
-    } +
-         +
-    for (String str : list) { // Iterate through the supplied list +
-        if (str.toLowerCase(Locale.ROOT).startsWith(remaining)) { +
-            builder.suggest(str); // Add every single entry to suggestions list. +
-        } +
-    } +
-    return builder.buildFuture(); // Create the CompletableFuture containing all the suggestions +
-+
-</code>+
  
-The SuggestionProvider is a functional interface that returns a CompletableFuture containing a list of suggestions. These suggestions are sent to client as a command is typed and can be changed while server is running. The SuggestionProvider provides a CommandContext and a SuggestionBuilder to allow determination of all the suggestions. The CommandSource can also be taken into account during the suggestion creation process as it is available through the CommandContext.+====== FAQ ======
  
-Though remember these are suggestions. The inputted command may not contain an argument you suggested so arguments are parsed without consideration for suggestions.+===== Why does my command not compile =====
  
-To use the suggestion you would append it right after the argument you want to suggest possible arguments for. This can be any argument and the normal client side exception popups will still work. Note this cannot be applied to literals.+There are two immediate possibilities for why this could occur.
  
-<code java [enable_line_numbers="true"]> +==== Catch or throw a CommandSyntaxException ==== 
-argument(argumentNameword()) + 
-.suggests(CompletionProviders.suggestedStrings()) +The solution to this issue is to make the run or suggest methods throw a CommandSyntaxException. Don't worrybrigadier will handle the exceptions and output the proper error message. 
-    .then(/*Rest of the command*/)); + 
-</code>+==== Issues with generics ==== 
 + 
 +You may have an issue with generic types once in a while. Verify you are using ''CommandManager.literal(...)'' or ''CommandManager.argument(...)'' instead ''LiteralArgumentBuilder'' or ''RequiredArgumentBuilder''
 + 
 +===== Can I register client side commands? ===== 
 + 
 +Fabric doesn't currently support client side commandsThere is a [[https://github.com/CottonMC/ClientCommands|third-party mod]] by the Cotton team that adds this functionality. 
 + 
 +===== Dark Arts ===== 
 + 
 +A few things we don't recommend, but are possible. 
 + 
 +==== Can I register commands in runtime? ==== 
 + 
 +You can do this but it is not recommended. You would get the ''CommandManager'' from the server and add anything commands you wish to it's ''CommandDispatcher''
 + 
 +After that you need to send the command tree to every player again using ''sendCommandTree(ServerPlayerEntity)''This is required because the client locally caches the command tree it receives during login (or when operator packets are sentfor local completions rich error messages. 
 + 
 +==== 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 effectsTo 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 ''sendCommandTree(ServerPlayerEntity)''. If you don't send the updated command tree, the client may think a command still exists, even though the server will fail execution. 
 + 
 +---- 
 + 
 +====== Sorry for the mess ====== 
 + 
 +**__Currently this article is being migrated, so things may be a mess. Below is are the parts of the article that are yet to be migrated to the new format.__**
  
-==== Requiring Permissions ====+===== Requirements =====
  
 Lets say you have a command you only want operators to be able to execute. This is where the ''requires'' method comes into play. The requires method has one argument of a Predicate<ServerCommandSource> which will supply a ServerCommandSource to test with and determine if the CommandSource can execute the command. Lets say you have a command you only want operators to be able to execute. This is where the ''requires'' method comes into play. The requires method has one argument of a Predicate<ServerCommandSource> which will supply a ServerCommandSource to test with and determine if the CommandSource can execute the command.
Line 172: Line 285:
 Nothing prevents someone from specifying calls to permissions implementations within the ''requires'' block. Just note that if permissions change, you need to re send the command tree. Nothing prevents someone from specifying calls to permissions implementations within the ''requires'' block. Just note that if permissions change, you need to re send the command tree.
  
-==== Exceptions ====+===== 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, as well as including richer details of the failure. 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.
Line 204: Line 317:
 You should remember that the Dynamic exceptions takes an object as an argument so you may have to cast the argument for your use. 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 (Aliases) ====+===== Redirects (Aliases) =====
  
 Redirects are Brigadier's form of aliases. Below is how Minecraft handles /msg have an alias of /tell and /w.  Redirects are Brigadier's form of aliases. Below is how Minecraft handles /msg have an alias of /tell and /w. 
Line 229: Line 342:
 The redirect tells brigadier to continue parsing the command at another command node. The redirect tells brigadier to continue parsing the command at another command node.
  
-==== Redirects (Chainable Commands) ====+===== Redirects (Chainable Commands) =====
 Commands such as ''/execute as @e[type=player] in the_end run tp ~ ~ ~'' are possible because of redirects. Below is an example of a chainable command: Commands such as ''/execute as @e[type=player] in the_end run tp ~ ~ ~'' are possible because of redirects. Below is an example of a chainable command:
  
Line 255: Line 368:
 </code> </code>
  
-===== ServerCommandSource =====+===== What can the ServerCommandSource do? =====
  
 A server command source provides some additional implementation specific context when a command is run. This includes the ability to get the entity that executed the command, the world the command was ran in or the server the command was run on. A server command source provides some additional implementation specific context when a command is run. This includes the ability to get the entity that executed the command, the world the command was ran in or the server the command was run on.
Line 294: Line 407:
 </code> </code>
  
-===== A few examples =====+===== Some example commands examples =====
  
 === Broadcast a message === === Broadcast a message ===
Line 315: Line 428:
 </code> </code>
  
-=== /giveMeDiamond ===+==== /giveMeDiamond ====
  
 First the basic code where we register "giveMeDiamond" as a literal and then an executes block to tell the dispatcher which method to run. First the basic code where we register "giveMeDiamond" as a literal and then an executes block to tell the dispatcher which method to run.
Line 346: Line 459:
 </code> </code>
  
-=== Antioch ===+==== Antioch ====
 ...lobbest thou thy Holy Hand Grenade of Antioch towards thy foe. ...lobbest thou thy Holy Hand Grenade of Antioch towards thy foe.
 who being naughty in My sight, shall snuff it. who being naughty in My sight, shall snuff it.
Line 383: Line 496:
 </code> </code>
  
-=== Finding Biomes via Command === +==== More examples coming soon ====
- +
-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 ''/locate'' +
-<code java [enable_line_numbers="true"]> +
-public class CommandLocateBiome { +
-    // First make method to register  +
-    public static void register(CommandDispatcher<ServerCommandSource> dispatcher) { +
-        LiteralCommandNode<ServerCommandSource> basenode = dispatcher.register(literal("findBiome"+
-                .then(argument("biome_identifier", identifier()).suggests(BiomeCompletionProvider.BIOMES) // We use Biome suggestions for identifier argument +
-                        .then(argument("distance", integer(0, 20000)) +
-                                .executes(ctx -> execute(ctx.getSource(), getIdentifier(ctx, "biome_identifier"), getInteger(ctx, "distance")))) +
-                        .executes(ctx -> execute(ctx.getSource(), getIdentifier(ctx, "biome_identifier"), 1000)))); +
-        // Register a redirect for /biome alias +
-        dispatcher.register(literal("biome"+
-                .redirect(basenode)); +
-    } +
- +
-    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 in the registry +
-            throw new SimpleCommandExceptionType(new TranslatableText("biome.not.exist", biomeId)).create(); +
-        } +
-         +
-        List<Biome> bio = new ArrayList<Biome>(); +
-        bio.add(biome); +
- +
-        ServerWorld world = source.getWorld(); +
-        BiomeSource bsource = world.getChunkManager().getChunkGenerator().getBiomeSource(); +
-        BlockPos loc = new BlockPos(source.getPosition()); +
- +
-        // This call will likely block the main thread +
-        BlockPos pos = bsource.locateBiome(loc.getX(), loc.getZ(), range, bio, new Random(world.getSeed())); +
-         +
-        // If null, a biome was not found +
-        if(pos == null) { +
-            throw new SimpleCommandExceptionType(new TranslatableText("biome.notfound", biome.getTranslationKey())).create(); +
-        } +
- +
-        int distance = MathHelper.floor(getDistance(loc.getX(), loc.getZ(), pos.getX(), pos.getZ())); +
-        // Popup text that can suggest commands. This is the exact same system that /locate uses. +
-        Text teleportButtonPopup Texts.bracketed(new TranslatableText("chat.coordinates", new Object[] { pos.getX(), "~", pos.getZ()})).styled((style) -> { +
-            style.setColor(Formatting.GREEN).setClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/tp @s " + pos.getX() + " ~ " + pos.getZ())).setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new TranslatableText("chat.coordinates.tooltip"))); +
-        }); +
-         +
-        source.sendFeedback(new TranslatableText("commands.locate.success", new Object[] { new TranslatableText(Registry.BIOME.get(biomeId).getTranslationKey()), teleportButtonPopup, distance}), false); +
- +
-        return 1; +
-    } +
-    // Just a normal old 2d distance method. +
-    private static float getDistance(int int_1, int int_2, int int_3, int int_4) { +
-        int int_5 int_3 - int_1; +
-        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 any modifications. +
-        public static final SuggestionProvider<ServerCommandSource> BIOMES SuggestionProviders.register(new Identifier("biomes"), (ctx, builder) -> { +
-            Registry.BIOME.getIds().stream().forEach(identifier -> builder.suggest(identifier.toString(), new TranslatableText(Registry.BIOME.get(identifier).getTranslationKey()))); +
-            return builder.buildFuture(); +
-        }); +
-         +
-    } +
-</code>+
  
 ===== Custom Argument Types ===== ===== Custom Argument Types =====
Line 586: Line 631:
 } }
 </file> </file>
-===== FAQ ===== 
- 
-=== What else can I send feedback to the CommandSource? === 
- 
-You use the Text classes (LiteralText, TranslatableText, KeybindText, etc). 
- 
-=== Why does my IDE complain saying that a method executed by my command needs to catch or throw a CommandSyntaxException === 
- 
-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 commands runtime? === 
- 
-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 ''CommandManager.sendCommandTree(ServerPlayerEntity)'' 
- 
-=== Can I unregister commands runtime? === 
- 
-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 ''CommandManager.sendCommandTree(ServerPlayerEntity)'' afterwards. 
- 
-=== Can I register client side commands? === 
- 
-Well Fabric currently doesn't support this natively but there is a mod by the Cotton team that adds this functionality where the commands do not run on the server and only on the client: 
-https://github.com/CottonMC/ClientCommands 
tutorial/commands.txt · Last modified: 2024/02/23 14:22 by allen1210