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 revisionBoth sides next revision
tutorial:commands [2019/07/29 19:19] – started fixing english errors but it's way too long lmao fudgetutorial:commands [2019/08/13 15:02] – Add line numbers to code, clarify issue with redirects. Add another Command example i509vcb
Line 16: Line 16:
 Below are a few examples of how the commands can be registered. Below are a few examples of how the commands can be registered.
  
-<code java>+<code java [enable_line_numbers="true"]>
 CommandRegistry.INSTANCE.register(false, dispatcher -> TutorialCommands.register(dispatcher)); // All commands are registered in a single class that references every command. CommandRegistry.INSTANCE.register(false, dispatcher -> TutorialCommands.register(dispatcher)); // All commands are registered in a single class that references every command.
   
Line 33: Line 33:
 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. 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>+<code java [enable_line_numbers="true"]>
 // The root of the command. This must be a literal argument. // The root of the command. This must be a literal argument.
 dispatcher.register(LiteralArgumentBuilder.literal("foo" dispatcher.register(LiteralArgumentBuilder.literal("foo"
Line 79: Line 79:
  
 And your imports would look something like this: And your imports would look something like this:
-<code java>+<code java [enable_line_numbers="true"]>
 import static com.mojang.brigadier.arguments.StringArgumentType.getString; // getString(ctx, "string") import static com.mojang.brigadier.arguments.StringArgumentType.getString; // getString(ctx, "string")
 import static com.mojang.brigadier.arguments.StringArgumentType.word; // word(), string(), greedyString() import static com.mojang.brigadier.arguments.StringArgumentType.word; // word(), string(), greedyString()
Line 104: Line 104:
  
 The example below is a dynamically changing SuggestionProvider that lists several words for a StringArgumentType to demonstrate how it works: The example below is a dynamically changing SuggestionProvider that lists several words for a StringArgumentType to demonstrate how it works:
-<code java>+<code java [enable_line_numbers="true"]>
 public static SuggestionProvider<ServerCommandSource> suggestedStrings() { public static SuggestionProvider<ServerCommandSource> suggestedStrings() {
     return (ctx, builder) -> getSuggestionsBuilder(builder, /*Access to a list here*/);     return (ctx, builder) -> getSuggestionsBuilder(builder, /*Access to a list here*/);
Line 131: Line 131:
 To use the suggestion you would append it right after the argument you want to recommend arguments for. This can be any argument and the normal client side exception popups will still work. Note this cannot be applied to literals. To use the suggestion you would append it right after the argument you want to recommend arguments for. This can be any argument and the normal client side exception popups will still work. Note this cannot be applied to literals.
  
-<code java>+<code java [enable_line_numbers="true"]>
 argument(argumentName, word()) argument(argumentName, word())
 .suggests(CompletionProviders.suggestedStrings()) .suggests(CompletionProviders.suggestedStrings())
Line 143: Line 143:
 For example this may look like the following: For example this may look like the following:
  
-<code java>+<code java [enable_line_numbers="true"]>
 dispatcher.register(literal("foo") dispatcher.register(literal("foo")
  .requires(source -> source.hasPermissionLevel(4))  .requires(source -> source.hasPermissionLevel(4))
Line 161: Line 161:
 Below is a coin flip command to show an example of exceptions in use. Below is a coin flip command to show an example of exceptions in use.
  
-<code java>+<code java [enable_line_numbers="true"]>
 dispatcher.register(CommandManager.literal("coinflip") dispatcher.register(CommandManager.literal("coinflip")
  .executes(ctx -> {  .executes(ctx -> {
Line 176: Line 176:
 Though you are not just limited to a single type of exception as Brigadier also supplies Dynamic exceptions. Though you are not just limited to a single type of exception as Brigadier also supplies Dynamic exceptions.
  
-<code java>+<code java [enable_line_numbers="true"]>
 DynamicCommandExceptionType used_name = new DynamicCommandExceptionType(name -> { DynamicCommandExceptionType used_name = new DynamicCommandExceptionType(name -> {
  return new LiteralText("The name: " + (String) name + " has been used");  return new LiteralText("The name: " + (String) name + " has been used");
Line 189: Line 189:
 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. 
  
-<code java>+<code java [enable_line_numbers="true"]>
 public static void register(CommandDispatcher<ServerCommandSource> dispatcher) { public static void register(CommandDispatcher<ServerCommandSource> dispatcher) {
     LiteralCommandNode node = registerMain(dispatcher); // Registers main command     LiteralCommandNode node = registerMain(dispatcher); // Registers main command
Line 210: Line 210:
 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. 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 also work in shortened aliases such as ''/mod thing <argument>'' having an alias of ''/thing <argument>'' as shown in the code below: +Redirects do not work in shortened aliases such as ''/mod thing <argument>'' having an alias of ''/thing <argument>'' as Brigadier does not allow forwarding nodes with children. Though you could use alternative methods to reduce the amount of duplicate code for this case.
- +
-<code java> +
-public static void register(CommandDispatcher<ServerCommandSource> dispatcher) { +
- LiteralCommandNode node = registerShortened(dispatcher); +
-        dispatcher.register(literal("mod"+
-     .then(literal("thing"+
-     .redirect(node))); // Option 2: /mod thing <argument> +
-+
- +
-public static LiteralCommandNode registerShortened(CommandDispatcher<ServerCommandSource> dispatcher) { // Option 1: /thing <argument> +
-    return dispatcher.register(literal("thing"+
- .then(argument("argument", word()) +
-     .executes(ctx -> execute(ctx)))); +
-+
-</code>+
  
 ===== ServerCommandSource ===== ===== ServerCommandSource =====
Line 231: Line 216:
 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 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
  
-<code java>+<code java [enable_line_numbers="true"]>
 ServerCommandSource source = ctx.getSource();  ServerCommandSource source = ctx.getSource(); 
 // Get the source. This will always work. // Get the source. This will always work.
Line 250: Line 235:
 The ServerCommandSource also provides other information about the sender of the command. The ServerCommandSource also provides other information about the sender of the command.
  
-<code java>+<code java [enable_line_numbers="true"]>
 source.getPosition();  source.getPosition(); 
 // Get's the sender's position as a Vec3 when the command was sent. This could be the location of the entity/command block or in the case of the console, the world's spawn point. // Get's the sender's position as a Vec3 when the command was sent. This could be the location of the entity/command block or in the case of the console, the world's spawn point.
Line 276: Line 261:
 === Broadcast a message === === Broadcast a message ===
  
-<code java> +<code java [enable_line_numbers="true"]
 public static void register(CommandDispatcher<ServerCommandSource> dispatcher){ public static void register(CommandDispatcher<ServerCommandSource> dispatcher){
     dispatcher.register(literal("broadcast")     dispatcher.register(literal("broadcast")
Line 297: Line 282:
 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.
  
-<code java>+<code java [enable_line_numbers="true"]>
 public static LiteralCommandNode register(CommandDispatcher<ServerCommandSource> dispatcher) { // You can also return a LiteralCommandNode for use with possible redirects public static LiteralCommandNode register(CommandDispatcher<ServerCommandSource> dispatcher) { // You can also return a LiteralCommandNode for use with possible redirects
     return dispatcher.register(literal("giveMeDiamond")     return dispatcher.register(literal("giveMeDiamond")
Line 306: Line 291:
 Then since we only want to give to players, we check if the CommandSource is a player. But we can use ''getPlayer'' and do both at the same time and throw an error if the source is not a player. Then since we only want to give to players, we check if the CommandSource is a player. But we can use ''getPlayer'' and do both at the same time and throw an error if the source is not a player.
  
-<code java>+<code java [enable_line_numbers="true"]>
 public static int giveDiamond(CommandContext<ServerCommandSource> ctx) throws CommandSyntaxException { public static int giveDiamond(CommandContext<ServerCommandSource> ctx) throws CommandSyntaxException {
     ServerCommandSource source = ctx.getSource();     ServerCommandSource source = ctx.getSource();
Line 315: Line 300:
 Then we add to the player's inventory, with a check to see if the inventory is full: Then we add to the player's inventory, with a check to see if the inventory is full:
  
-<code java>+<code java [enable_line_numbers="true"]>
     if(!player.inventory.insertStack(new ItemStack(Items.DIAMOND))){     if(!player.inventory.insertStack(new ItemStack(Items.DIAMOND))){
         throw new SimpleCommandExceptionType(new TranslateableText("inventory.isfull")).create();         throw new SimpleCommandExceptionType(new TranslateableText("inventory.isfull")).create();
Line 331: Line 316:
 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. 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>+<code java [enable_line_numbers="true"]>
 public static void register(CommandDispatcher<ServerCommandSource> dispatcher) { public static void register(CommandDispatcher<ServerCommandSource> dispatcher) {
     dispatcher.register(literal("antioch")     dispatcher.register(literal("antioch")
Line 342: Line 327:
 Then the creation and messages behind the joke. Then the creation and messages behind the joke.
  
-<code java>+<code java [enable_line_numbers="true"]>
 public static int antioch(ServerCommandSource source, BlockPos blockPos) throws CommandSyntaxException {  public static int antioch(ServerCommandSource source, BlockPos blockPos) throws CommandSyntaxException { 
   
Line 356: Line 341:
     return 1;     return 1;
 } }
 +</code>
 +
 +=== 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 ''/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 redirect
 +        dispatcher.register(literal("biome")
 +                .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 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());
 +        // Now here is the heaviest part of the method.
 +        BlockPos pos = bsource.locateBiome(loc.getX(), loc.getZ(), range, bio, new Random(world.getSeed()));
 +        
 +        // Since this method can return null if it failed to find a biome
 +        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_1x) -> {
 +            style_1x.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", new Object[0])));
 +        });
 +        
 +        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 modification.
 +        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> </code>
  
tutorial/commands.txt · Last modified: 2024/02/23 14:22 by allen1210