/* * This file is part of ComputerCraft - http://www.computercraft.info * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.command.builder; import com.mojang.brigadier.Command; import com.mojang.brigadier.arguments.ArgumentType; import com.mojang.brigadier.builder.ArgumentBuilder; import com.mojang.brigadier.builder.RequiredArgumentBuilder; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.tree.CommandNode; import dan200.computercraft.shared.command.arguments.RepeatArgumentType; import net.minecraft.commands.CommandSourceStack; import javax.annotation.Nullable; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.function.Predicate; import java.util.function.Supplier; import static dan200.computercraft.shared.command.Exceptions.ARGUMENT_EXPECTED; import static dan200.computercraft.shared.command.builder.HelpingArgumentBuilder.literal; /** * An alternative way of building command nodes, so one does not have to nest. * {@link ArgumentBuilder#then(CommandNode)}s. * * @param The command source we consume. */ public class CommandBuilder implements CommandNodeBuilder> { private final List> args = new ArrayList<>(); private @Nullable Predicate requires; public static CommandBuilder args() { return new CommandBuilder<>(); } public static CommandBuilder command(String literal) { var builder = new CommandBuilder(); builder.args.add(literal(literal)); return builder; } public CommandBuilder requires(Predicate predicate) { requires = requires == null ? predicate : requires.and(predicate); return this; } public CommandBuilder arg(String name, ArgumentType type) { args.add(RequiredArgumentBuilder.argument(name, type)); return this; } public CommandNodeBuilder>> argManyValue(String name, ArgumentType type, List empty) { return argMany(name, type, () -> empty); } public CommandNodeBuilder>> argManyValue(String name, ArgumentType type, T defaultValue) { return argManyValue(name, type, Collections.singletonList(defaultValue)); } public CommandNodeBuilder>> argMany(String name, ArgumentType type, Supplier> empty) { return argMany(name, RepeatArgumentType.some(type, ARGUMENT_EXPECTED), empty); } public CommandNodeBuilder>> argManyFlatten(String name, ArgumentType> type, Supplier> empty) { return argMany(name, RepeatArgumentType.someFlat(type, ARGUMENT_EXPECTED), empty); } private CommandNodeBuilder>> argMany(String name, RepeatArgumentType type, Supplier> empty) { if (args.isEmpty()) throw new IllegalStateException("Cannot have empty arg chain builder"); return command -> { // The node for no arguments var tail = tail(ctx -> command.run(ctx, empty.get())); // The node for one or more arguments ArgumentBuilder moreArg = RequiredArgumentBuilder .>argument(name, type) .executes(ctx -> command.run(ctx, getList(ctx, name))); // Chain all of them together! tail.then(moreArg); return link(tail); }; } @SuppressWarnings("unchecked") private static List getList(CommandContext context, String name) { return (List) context.getArgument(name, List.class); } @Override public CommandNode executes(Command command) { if (args.isEmpty()) throw new IllegalStateException("Cannot have empty arg chain builder"); return link(tail(command)); } private ArgumentBuilder tail(Command command) { var defaultTail = args.get(args.size() - 1); defaultTail.executes(command); if (requires != null) defaultTail.requires(requires); return defaultTail; } private CommandNode link(ArgumentBuilder tail) { for (var i = args.size() - 2; i >= 0; i--) tail = args.get(i).then(tail); return tail.build(); } }