From b409eadffa57db456d8b9d1f8f31b9ba17a21b1a Mon Sep 17 00:00:00 2001 From: Konstantin Shandurenko Date: Tue, 23 Feb 2021 09:06:19 +0300 Subject: [PATCH] ArgumentEnum and /horse command for demo scene --- .../builder/arguments/ArgumentEnum.java | 64 ++++++++++++++++ .../builder/arguments/ArgumentType.java | 5 ++ src/test/java/demo/Main.java | 1 + src/test/java/demo/commands/HorseCommand.java | 73 +++++++++++++++++++ 4 files changed, 143 insertions(+) create mode 100644 src/main/java/net/minestom/server/command/builder/arguments/ArgumentEnum.java create mode 100644 src/test/java/demo/commands/HorseCommand.java diff --git a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentEnum.java b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentEnum.java new file mode 100644 index 000000000..03676e898 --- /dev/null +++ b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentEnum.java @@ -0,0 +1,64 @@ +package net.minestom.server.command.builder.arguments; + +import net.minestom.server.command.builder.NodeMaker; +import net.minestom.server.command.builder.exception.ArgumentSyntaxException; +import net.minestom.server.network.packet.server.play.DeclareCommandsPacket; +import org.jetbrains.annotations.NotNull; + +import java.util.Locale; +import java.util.function.Consumer; + +/** + * Created by k.shandurenko on 23.02.2021 + */ +@SuppressWarnings("rawtypes") +public class ArgumentEnum extends Argument { + + public final static int NOT_ENUM_VALUE_ERROR = 1; + + private final Class enumClass; + private final E[] values; + + public ArgumentEnum(@NotNull String id, Class enumClass) { + super(id); + this.enumClass = enumClass; + this.values = enumClass.getEnumConstants(); + } + + @NotNull + @Override + public E parse(@NotNull String input) throws ArgumentSyntaxException { + for (E value : this.values) { + if (value.name().equalsIgnoreCase(input)) { + return value; + } + } + throw new ArgumentSyntaxException("Not a " + this.enumClass.getSimpleName() + " value", input, NOT_ENUM_VALUE_ERROR); + } + + @Override + public void processNodes(@NotNull NodeMaker nodeMaker, boolean executable) { + // Add the single word properties + parser + final Consumer wordConsumer = node -> { + node.parser = "brigadier:string"; + node.properties = packetWriter -> { + packetWriter.writeVarInt(0); // Single word + }; + }; + + // Create a primitive array for mapping + DeclareCommandsPacket.Node[] nodes = new DeclareCommandsPacket.Node[this.values.length]; + + // Create a node for each restrictions as literal + for (int i = 0; i < nodes.length; i++) { + DeclareCommandsPacket.Node argumentNode = new DeclareCommandsPacket.Node(); + + argumentNode.flags = DeclareCommandsPacket.getFlag(DeclareCommandsPacket.NodeType.LITERAL, + executable, false, false); + argumentNode.name = this.values[i].name().toLowerCase(Locale.ROOT); + wordConsumer.accept(argumentNode); + nodes[i] = argumentNode; + } + nodeMaker.addNodes(nodes); + } +} diff --git a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentType.java b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentType.java index 5edab32de..5f40d2b79 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentType.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentType.java @@ -79,6 +79,11 @@ public class ArgumentType { return new ArgumentCommand(id); } + @SuppressWarnings("rawtypes") + public static ArgumentEnum Enum(@NotNull String id, @NotNull Class enumClass) { + return new ArgumentEnum<>(id, enumClass); + } + // Minecraft specific arguments public static ArgumentColor Color(@NotNull String id) { diff --git a/src/test/java/demo/Main.java b/src/test/java/demo/Main.java index 438b4e278..c49111ed3 100644 --- a/src/test/java/demo/Main.java +++ b/src/test/java/demo/Main.java @@ -43,6 +43,7 @@ public class Main { commandManager.register(new TitleCommand()); commandManager.register(new BookCommand()); commandManager.register(new ShootCommand()); + commandManager.register(new HorseCommand()); commandManager.setUnknownCommandCallback((sender, command) -> sender.sendMessage("unknown command")); diff --git a/src/test/java/demo/commands/HorseCommand.java b/src/test/java/demo/commands/HorseCommand.java new file mode 100644 index 000000000..4491649ac --- /dev/null +++ b/src/test/java/demo/commands/HorseCommand.java @@ -0,0 +1,73 @@ +package demo.commands; + +import net.minestom.server.command.CommandSender; +import net.minestom.server.command.builder.Arguments; +import net.minestom.server.command.builder.Command; +import net.minestom.server.command.builder.arguments.ArgumentType; +import net.minestom.server.command.builder.exception.ArgumentSyntaxException; +import net.minestom.server.entity.EntityType; +import net.minestom.server.entity.Player; +import net.minestom.server.entity.type.animal.EntityHorse; + +import java.util.Locale; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class HorseCommand extends Command { + + public HorseCommand() { + super("horse"); + setCondition(this::condition); + setDefaultExecutor(this::defaultExecutor); + var babyArg = ArgumentType.Boolean("baby"); + var markingArg = ArgumentType.Enum("marking", EntityHorse.Marking.class); + var colorArg = ArgumentType.Enum("color", EntityHorse.Color.class); + setArgumentCallback(this::onBabyError, babyArg); + setArgumentCallback(this::onMarkingError, markingArg); + setArgumentCallback(this::onColorError, colorArg); + addSyntax(this::onHorseCommand, babyArg, markingArg, colorArg); + } + + private boolean condition(CommandSender sender, String commandString) { + if (!sender.isPlayer()) { + sender.sendMessage("The command is only available for player"); + return false; + } + return true; + } + + private void defaultExecutor(CommandSender sender, Arguments args) { + sender.sendMessage("Correct usage: horse [baby] [marking] [color]"); + } + + private void onBabyError(CommandSender sender, ArgumentSyntaxException exception) { + sender.sendMessage("SYNTAX ERROR: '" + exception.getInput() + "' should be replaced by 'true' or 'false'"); + } + + private void onMarkingError(CommandSender sender, ArgumentSyntaxException exception) { + String values = Stream.of(EntityHorse.Marking.values()) + .map(value -> "'" + value.name().toLowerCase(Locale.ROOT) + "'") + .collect(Collectors.joining(", ")); + sender.sendMessage("SYNTAX ERROR: '" + exception.getInput() + "' should be replaced by " + values + "."); + } + + private void onColorError(CommandSender sender, ArgumentSyntaxException exception) { + String values = Stream.of(EntityHorse.Color.values()) + .map(value -> "'" + value.name().toLowerCase(Locale.ROOT) + "'") + .collect(Collectors.joining(", ")); + sender.sendMessage("SYNTAX ERROR: '" + exception.getInput() + "' should be replaced by " + values + "."); + } + + private void onHorseCommand(CommandSender sender, Arguments args) { + var player = (Player) sender; + + boolean baby = args.get("baby"); + EntityHorse.Marking marking = args.get("marking"); + EntityHorse.Color color = args.get("color"); + var horse = (EntityHorse) EntityType.HORSE.createFromPosition(player.getPosition()); + horse.setBaby(baby); + horse.setVariant(new EntityHorse.Variant(marking, color)); + horse.setInstance(player.getInstance()); + } + +}