9
0
mirror of https://github.com/LeavesMC/Leaves.git synced 2025-12-29 20:09:23 +00:00

fix: fix bot action command

This commit is contained in:
MC_XiaoHei
2025-08-23 13:43:40 +08:00
parent 55061cfc5e
commit 285e70ac98
19 changed files with 413 additions and 85 deletions

View File

@@ -59,12 +59,13 @@ public abstract class ServerBotAction<E extends ServerBotAction<E>> {
public abstract Object asCraft();
public List<Pair<String, String>> provideReadableActionData() {
return new ArrayList<>();
public void provideActionData(@NotNull ActionData data) {
}
public String getReadableActionDataString() {
return provideReadableActionData().stream()
public String getActionDataString() {
ActionData data = new ActionData(new ArrayList<>());
provideActionData(data);
return data.raw.stream()
.map(pair -> pair.getLeft() + "=" + pair.getRight())
.reduce((a, b) -> a + ", " + b)
.orElse("No arguments");
@@ -247,4 +248,12 @@ public abstract class ServerBotAction<E extends ServerBotAction<E>> {
public void setOnStop(Consumer<E> onStop) {
this.onStop = onStop;
}
public record ActionData(
List<Pair<String, String>> raw
) {
public void add(String key, String value) {
raw.add(Pair.of(key, value));
}
}
}

View File

@@ -98,6 +98,16 @@ public class ServerLookAction extends ServerBotAction<ServerLookAction> {
return target;
}
@Override
public void provideActionData(@NotNull ActionData data) {
super.provideActionData(data);
if (target != null) {
data.add("target", target.getName().getString());
} else {
data.add("position", String.format("(%.2f, %.2f, %.2f)", pos.getX(), pos.getY(), pos.getZ()));
}
}
@Override
public boolean doTick(@NotNull ServerBot bot) {
if (target != null) {

View File

@@ -22,8 +22,8 @@ public class ServerMountAction extends ServerBotAction<ServerMountAction> {
Location center = bot.getBukkitEntity().getLocation();
List<Vehicle> vehicles = center.getNearbyEntitiesByType(
Vehicle.class,
3,
vehicle -> manhattanDistance(bot, ((CraftEntity) vehicle).getHandle()) <= 2
4,
vehicle -> manhattanDistance(bot, ((CraftEntity) vehicle).getHandle()) <= 3
).stream().sorted(Comparator.comparingDouble(
(vehicle) -> center.distanceSquared(vehicle.getLocation())
)).toList();

View File

@@ -1,6 +1,7 @@
package org.leavesmc.leaves.bot.agent.actions;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.entity.bot.action.MoveAction.MoveDirection;
@@ -9,27 +10,36 @@ import org.leavesmc.leaves.event.bot.BotActionStopEvent;
import org.leavesmc.leaves.neo_command.CommandContext;
import java.util.Arrays;
import java.util.Map;
import static java.util.stream.Collectors.toMap;
import static org.leavesmc.leaves.neo_command.leaves.ArgumentSuggestions.strings;
public class ServerMoveAction extends ServerStateBotAction<ServerMoveAction> {
private static final Map<String, MoveDirection> NAME_TO_DIRECTION = Arrays.stream(MoveDirection.values()).collect(toMap(
it -> it.name,
it -> it
));
private MoveDirection direction = MoveDirection.FORWARD;
public ServerMoveAction() {
super("move", ServerMoveAction::new);
this.addArgument("direction", StringArgumentType.word())
.suggests(strings(Arrays.stream(MoveDirection.values()).map(MoveDirection::name).toList()));
.suggests(strings(
Arrays.stream(MoveDirection.values())
.map((it) -> it.name)
.toList()
));
}
@Override
public void loadCommand(@NotNull CommandContext context) {
public void loadCommand(@NotNull CommandContext context) throws CommandSyntaxException {
String raw = context.getArgument("direction", String.class);
try {
this.direction = MoveDirection.valueOf(raw);
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("Invalid move direction: " + raw);
MoveDirection direction = NAME_TO_DIRECTION.get(raw);
if (direction == null) {
throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument().create();
}
this.direction = direction;
}
@Override
@@ -54,6 +64,12 @@ public class ServerMoveAction extends ServerStateBotAction<ServerMoveAction> {
return true;
}
@Override
public void provideActionData(@NotNull ActionData data) {
super.provideActionData(data);
data.add("direction", direction.name);
}
public MoveDirection getDirection() {
return direction;
}

View File

@@ -56,6 +56,13 @@ public class ServerRotationAction extends ServerBotAction<ServerRotationAction>
return this.pitch;
}
@Override
public void provideActionData(@NotNull ActionData data) {
super.provideActionData(data);
data.add("yaw", DF.format(this.yaw));
data.add("pitch", DF.format(this.pitch));
}
@Override
@NotNull
public CompoundTag save(@NotNull CompoundTag nbt) {

View File

@@ -1,12 +1,9 @@
package org.leavesmc.leaves.bot.agent.actions;
import net.minecraft.network.chat.Component;
import org.apache.commons.lang3.tuple.Pair;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.neo_command.CommandContext;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
import static com.mojang.brigadier.arguments.IntegerArgumentType.integer;
@@ -35,12 +32,11 @@ public abstract class ServerTimerBotAction<E extends ServerTimerBotAction<E>> ex
}
@Override
public List<Pair<String, String>> provideReadableActionData() {
return new ArrayList<>(List.of(
Pair.of("delay", String.valueOf(this.getStartDelayTick())),
Pair.of("interval", String.valueOf(this.getDoIntervalTick())),
Pair.of("do_number", String.valueOf(this.getDoNumber())),
Pair.of("remaining_do_number", String.valueOf(this.getDoNumberRemaining()))
));
public void provideActionData(@NotNull ActionData data) {
super.provideActionData(data);
data.add("delay", String.valueOf(this.getStartDelayTick()));
data.add("interval", String.valueOf(this.getDoIntervalTick()));
data.add("do_number", String.valueOf(this.getDoNumber()));
data.add("remaining_do_number", String.valueOf(this.getDoNumberRemaining()));
}
}

View File

@@ -97,6 +97,13 @@ public abstract class ServerUseBotAction<T extends ServerUseBotAction<T>> extend
this.alreadyUsedTick++;
}
@Override
public void provideActionData(@NotNull ActionData data) {
super.provideActionData(data);
data.add("use_timeout", String.valueOf(this.useTickTimeout));
data.add("already_used_tick", String.valueOf(this.alreadyUsedTick));
}
@Override
@NotNull
public CompoundTag save(@NotNull CompoundTag nbt) {

View File

@@ -4,6 +4,7 @@ import com.mojang.brigadier.Command;
import com.mojang.brigadier.RedirectModifier;
import com.mojang.brigadier.context.ParsedCommandNode;
import com.mojang.brigadier.context.StringRange;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.tree.CommandNode;
import net.minecraft.commands.CommandSourceStack;
import org.bukkit.command.CommandSender;
@@ -52,13 +53,13 @@ public class CommandContext {
}
@SuppressWarnings("unchecked")
public <V, T> @NotNull V getCustomArgument(final Class<? extends CustomArgumentNode<V, T>> nodeClass) {
public <V, T> @NotNull V getCustomArgument(final Class<? extends CustomArgumentNode<V, T>> nodeClass) throws CommandSyntaxException {
String name = getNameForNode(nodeClass);
T raw = (T) source.getArgument(name, Object.class);
return CustomArgumentNode.transform(nodeClass, raw);
}
public <V> @NotNull V getArgumentOrDefault(final Class<? extends ArgumentNode<V>> nodeClass, final V defaultValue) {
public <V> V getArgumentOrDefault(final Class<? extends ArgumentNode<V>> nodeClass, final V defaultValue) {
try {
return getArgument(nodeClass);
} catch (IllegalArgumentException e) {
@@ -74,7 +75,7 @@ public class CommandContext {
}
}
public <V, T> V getCustomArgumentOrDefault(final Class<? extends CustomArgumentNode<V, T>> nodeClass, final V defaultValue) {
public <V, T> V getCustomArgumentOrDefault(final Class<? extends CustomArgumentNode<V, T>> nodeClass, final V defaultValue) throws CommandSyntaxException {
try {
return getCustomArgument(nodeClass);
} catch (IllegalArgumentException e) {
@@ -121,4 +122,8 @@ public class CommandContext {
public boolean isForked() {
return source.isForked();
}
public com.mojang.brigadier.context.CommandContext<CommandSourceStack> getMojangContext() {
return source;
}
}

View File

@@ -1,6 +1,7 @@
package org.leavesmc.leaves.neo_command;
import com.mojang.brigadier.builder.ArgumentBuilder;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.commands.CommandSourceStack;
import org.jetbrains.annotations.NotNull;
@@ -30,7 +31,7 @@ public abstract class CommandNode {
protected abstract ArgumentBuilder<CommandSourceStack, ?> compileBase();
protected boolean execute(CommandContext context) {
protected boolean execute(CommandContext context) throws CommandSyntaxException {
return true;
}

View File

@@ -2,6 +2,7 @@ package org.leavesmc.leaves.neo_command;
import com.mojang.brigadier.builder.ArgumentBuilder;
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.commands.CommandSourceStack;
import org.jetbrains.annotations.NotNull;
@@ -17,7 +18,7 @@ public class CustomArgumentNode<T, B> extends ArgumentNode<B> {
TYPES.put(getClass(), argumentType);
}
public static <T, B> T transform(Class<? extends CustomArgumentNode<T, B>> nodeClass, B base) {
public static <T, B> T transform(Class<? extends CustomArgumentNode<T, B>> nodeClass, B base) throws CommandSyntaxException {
@SuppressWarnings("unchecked")
CustomArgumentType<T, B> type = (CustomArgumentType<T, B>) TYPES.get(nodeClass);
if (type == null) {

View File

@@ -11,7 +11,7 @@ public interface CustomArgumentType<T, B> {
ArgumentType<B> getBaseArgumentType();
T transform(B value);
T transform(B value) throws CommandSyntaxException;
CompletableFuture<Suggestions> getSuggestions(CommandContext context, SuggestionsBuilder builder) throws CommandSyntaxException;
}

View File

@@ -2,8 +2,10 @@ package org.leavesmc.leaves.neo_command.bot;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import net.minecraft.network.chat.Component;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.leavesmc.leaves.bot.ServerBot;
@@ -22,16 +24,19 @@ public class BotArgument implements CustomArgumentType<ServerBot, String> {
}
@Override
public ServerBot transform(String value) {
public ServerBot transform(String value) throws CommandSyntaxException {
CraftBot craftBot = (CraftBot) Bukkit.getBotManager().getBot(value);
if (craftBot == null) {
return null;
throw new CommandSyntaxException(
CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument(),
Component.literal("Bot with name '" + value + "' does not exist")
);
}
return craftBot.getHandle();
}
@Override
public CompletableFuture<Suggestions> getSuggestions(CommandContext context, SuggestionsBuilder builder) {
public CompletableFuture<Suggestions> getSuggestions(CommandContext context, SuggestionsBuilder builder) throws CommandSyntaxException {
Collection<Bot> bots = Bukkit.getBotManager().getBots();
if (bots.isEmpty()) {
return builder

View File

@@ -6,6 +6,8 @@ import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.LeavesConfig;
import org.leavesmc.leaves.neo_command.LiteralNode;
import org.leavesmc.leaves.neo_command.bot.subcommands.ActionCommand;
import org.leavesmc.leaves.neo_command.bot.subcommands.CreateCommand;
import org.leavesmc.leaves.neo_command.bot.subcommands.ListCommand;
public class BotCommand extends LiteralNode {
private static final String PERM_BASE = "bukkit.command.bot";
@@ -13,7 +15,9 @@ public class BotCommand extends LiteralNode {
public BotCommand() {
super("bot_neo");
this.children(
ActionCommand::new
ActionCommand::new,
ListCommand::new,
CreateCommand::new
);
}

View File

@@ -1,8 +1,8 @@
package org.leavesmc.leaves.neo_command.bot.subcommands;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.commands.CommandSourceStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.neo_command.CommandContext;
import org.leavesmc.leaves.neo_command.CustomArgumentNode;
@@ -35,13 +35,8 @@ public class ActionCommand extends LiteralNode {
);
}
public static @Nullable ServerBot getBot(@NotNull CommandContext context) {
try {
return context.getCustomArgument(BotArgument.class);
} catch (IllegalArgumentException e) {
context.getSender().sendMessage("This bot does not exist.");
return null;
}
public static @NotNull ServerBot getBot(@NotNull CommandContext context) throws CommandSyntaxException {
return context.getCustomArgument(BotArgument.class);
}
}
}

View File

@@ -0,0 +1,152 @@
package org.leavesmc.leaves.neo_command.bot.subcommands;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.kyori.adventure.text.format.NamedTextColor;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.arguments.DimensionArgument;
import net.minecraft.commands.arguments.coordinates.Coordinates;
import net.minecraft.commands.arguments.coordinates.Vec3Argument;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.phys.Vec3;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.entity.Entity;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.LeavesConfig;
import org.leavesmc.leaves.bot.BotCreateState;
import org.leavesmc.leaves.bot.BotList;
import org.leavesmc.leaves.event.bot.BotCreateEvent;
import org.leavesmc.leaves.neo_command.ArgumentNode;
import org.leavesmc.leaves.neo_command.CommandContext;
import org.leavesmc.leaves.neo_command.LiteralNode;
import static net.kyori.adventure.text.Component.text;
import static net.minecraft.commands.arguments.DimensionArgument.getDimension;
public class CreateCommand extends LiteralNode {
public CreateCommand() {
super("create");
children(NameArgument::new);
}
protected static boolean handleCreateCommand(@NotNull CommandContext context) throws CommandSyntaxException {
CommandSender sender = context.getSender();
String name = context.getArgument(NameArgument.class);
if (!canCreate(sender, name)) {
return false;
}
String skinName = context.getArgumentOrDefault(SkinNameArgument.class, name);
World world;
try {
world = getDimension(context.getMojangContext(), "world").getWorld();
} catch (IllegalArgumentException e) {
if (!(sender instanceof Entity entity)) {
sender.sendMessage(text("Must specify world and location when executed by console", NamedTextColor.RED));
return false;
}
world = entity.getWorld();
}
Location location = Bukkit.getWorlds().getFirst().getSpawnLocation();
Coordinates coords = context.getArgumentOrDefault(LocationArgument.class, null);
if (coords != null) {
Vec3 vec3 = coords.getPosition(context.getSource());
location = new Location(world, vec3.x, vec3.y, vec3.z);
} else if (sender instanceof Entity entity) {
location = entity.getLocation();
}
BotCreateState
.builder(name, location)
.createReason(BotCreateEvent.CreateReason.COMMAND)
.skinName(skinName)
.creator(sender)
.spawnWithSkin(null);
return true;
}
private static boolean canCreate(CommandSender sender, @NotNull String name) {
BotList botList = BotList.INSTANCE;
if (!name.matches("^[a-zA-Z0-9_]{4,16}$")) {
sender.sendMessage(text("This name is illegal", NamedTextColor.RED));
return false;
}
if (Bukkit.getPlayerExact(name) != null || botList.getBotByName(name) != null) {
sender.sendMessage(text("This bot is already in server", NamedTextColor.RED));
return false;
}
if (LeavesConfig.modify.fakeplayer.unableNames.contains(name)) {
sender.sendMessage(text("This name is not allowed", NamedTextColor.RED));
return false;
}
if (botList.bots.size() >= LeavesConfig.modify.fakeplayer.limit) {
sender.sendMessage(text("Bot number limit exceeded", NamedTextColor.RED));
return false;
}
return true;
}
private static class NameArgument extends ArgumentNode<String> {
public NameArgument() {
super("name", StringArgumentType.word());
children(SkinNameArgument::new);
}
@Override
protected boolean execute(CommandContext context) throws CommandSyntaxException {
return handleCreateCommand(context);
}
}
private static class SkinNameArgument extends ArgumentNode<String> {
public SkinNameArgument() {
super("skin_name", StringArgumentType.word());
children(WorldArgument::new);
}
@Override
protected boolean execute(CommandContext context) throws CommandSyntaxException {
return handleCreateCommand(context);
}
}
private static class WorldArgument extends ArgumentNode<ResourceLocation> {
public WorldArgument() {
super("world", DimensionArgument.dimension());
children(LocationArgument::new);
}
@Override
protected boolean requires(@NotNull CommandSourceStack source) {
return source.getSender() instanceof ConsoleCommandSender;
}
}
private static class LocationArgument extends ArgumentNode<Coordinates> {
public LocationArgument() {
super("location", Vec3Argument.vec3(true));
}
@Override
protected boolean execute(CommandContext context) throws CommandSyntaxException {
return handleCreateCommand(context);
}
}
}

View File

@@ -0,0 +1,98 @@
package org.leavesmc.leaves.neo_command.bot.subcommands;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import io.papermc.paper.adventure.PaperAdventure;
import net.kyori.adventure.text.Component;
import net.minecraft.commands.arguments.DimensionArgument;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.player.Player;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.craftbukkit.CraftWorld;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.leavesmc.leaves.LeavesConfig;
import org.leavesmc.leaves.bot.BotList;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.neo_command.ArgumentNode;
import org.leavesmc.leaves.neo_command.CommandContext;
import org.leavesmc.leaves.neo_command.LiteralNode;
import java.util.List;
import java.util.Objects;
import static net.kyori.adventure.text.Component.join;
import static net.kyori.adventure.text.Component.text;
import static net.kyori.adventure.text.JoinConfiguration.noSeparators;
import static net.kyori.adventure.text.event.HoverEvent.showText;
import static net.kyori.adventure.text.format.NamedTextColor.*;
import static net.minecraft.commands.arguments.DimensionArgument.getDimension;
public class ListCommand extends LiteralNode {
public ListCommand() {
super("list");
children(WorldArgument::new);
}
@Override
protected boolean execute(@NotNull CommandContext context) throws CommandSyntaxException {
Component msg = Bukkit.getWorlds().stream()
.map(ListCommand::getBotListMessage)
.filter(Objects::nonNull)
.reduce((a, b) -> a.append(text("\n")).append(b))
.orElseGet(() -> text("No bots on the server", GRAY));
context.getSender().sendMessage(join(noSeparators(),
text("Total bot number: ", GRAY),
text(BotList.INSTANCE.bots.size(), AQUA).hoverEvent(showText(text("current bot count"))),
text("/", GRAY),
text(LeavesConfig.modify.fakeplayer.limit, AQUA).hoverEvent(showText(text("bot count limit")))
));
context.getSender().sendMessage(msg);
return true;
}
protected static @Nullable Component getBotListMessage(@NotNull World world) {
BotList botList = BotList.INSTANCE;
List<ServerBot> botsInLevel = botList.bots.stream()
.filter((bot) -> bot.getBukkitEntity().getWorld().equals(world))
.toList();
if (botsInLevel.isEmpty()) {
return null;
}
Component botsMsg = botsInLevel.stream()
.map(Player::getDisplayName)
.map(PaperAdventure::asAdventure)
.reduce((a, b) -> a.append(text(", ", GRAY)).append(b))
.get();
String worldLocation = ((CraftWorld) world).getHandle().dimension().location().toString();
return join(noSeparators(),
text(world.getName(), AQUA).hoverEvent(showText(text(worldLocation))),
text(" (" + botsInLevel.size() + ")\n", GRAY),
botsMsg
);
}
private static class WorldArgument extends ArgumentNode<ResourceLocation> {
protected WorldArgument() {
super("world", DimensionArgument.dimension());
}
@Override
protected boolean execute(@NotNull CommandContext context) throws CommandSyntaxException {
ServerLevel dimension = getDimension(context.getMojangContext(), "world");
Component botListMessage = getBotListMessage(dimension.getWorld());
CommandSender sender = context.getSender();
if (botListMessage == null) {
sender.sendMessage(text("No bots in that world", RED));
} else {
sender.sendMessage(text("Bot in ").append(botListMessage));
}
return true;
}
}
}

View File

@@ -1,5 +1,7 @@
package org.leavesmc.leaves.neo_command.bot.subcommands.action;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.bot.agent.actions.ServerBotAction;
@@ -9,6 +11,7 @@ import org.leavesmc.leaves.neo_command.bot.subcommands.ActionCommand;
import java.util.List;
import static io.papermc.paper.adventure.PaperAdventure.asAdventure;
import static net.kyori.adventure.text.Component.join;
import static net.kyori.adventure.text.Component.text;
import static net.kyori.adventure.text.JoinConfiguration.spaces;
@@ -23,24 +26,25 @@ public class ListCommand extends LiteralNode {
}
@Override
protected boolean execute(@NotNull CommandContext context) {
protected boolean execute(@NotNull CommandContext context) throws CommandSyntaxException {
ServerBot bot = ActionCommand.BotArgument.getBot(context);
if (bot == null) {
return false;
}
CommandSender sender = context.getSender();
List<ServerBotAction<?>> actions = bot.getBotActions();
if (actions.isEmpty()) {
context.getSender().sendMessage("This bot has no active actions");
sender.sendMessage(text("This bot has no active actions", GRAY));
return true;
}
context.getSender().sendMessage(bot.getScoreboardName() + "'s action list:");
sender.sendMessage(
asAdventure(bot.getDisplayName())
.append(text("'s action list:", GRAY))
);
for (int i = 0; i < actions.size(); i++) {
ServerBotAction<?> action = actions.get(i);
context.getSender().sendMessage(join(spaces(),
sender.sendMessage(join(spaces(),
text(i, GRAY),
text(action.getName(), AQUA).hoverEvent(showText(text(action.getReadableActionDataString())))
text(action.getName(), AQUA).hoverEvent(showText(text(action.getActionDataString())))
));
}

View File

@@ -38,21 +38,20 @@ public class StartCommand extends LiteralNode {
.forEach(this::children);
}
private boolean executor(CommandContext context, @NotNull ServerBotAction<?> action) throws CommandSyntaxException {
private boolean handleStartCommand(CommandContext context, @NotNull ServerBotAction<?> action) throws CommandSyntaxException {
ServerBot bot = getBot(context);
CommandSender sender = context.getSender();
if (bot == null) {
return false;
}
action.loadCommand(context);
if (bot.addBotAction(action, sender)) {
sender.sendMessage(join(spaces(),
text("Action", GRAY),
text(action.getName(), AQUA).hoverEvent(showText(text(action.getReadableActionDataString()))),
text(action.getName(), AQUA).hoverEvent(showText(text(action.getActionDataString()))),
text("has been issued to", GRAY),
asAdventure(bot.getDisplayName())
));
}
return true;
}
@@ -63,16 +62,17 @@ public class StartCommand extends LiteralNode {
protected ArgumentBuilder<CommandSourceStack, ?> compile() {
ArgumentBuilder<CommandSourceStack, ?> builder = super.compile();
for (Map.Entry<Integer, List<Pair<String, WrappedArgument<?>>>> entry : action.getArguments().entrySet()) {
Map<Integer, List<Pair<String, WrappedArgument<?>>>> arguments = action.getArguments();
Command<CommandSourceStack> executor = context -> {
if (handleStartCommand(new CommandContext(context), action)) {
return Command.SINGLE_SUCCESS;
} else {
return 0;
}
};
for (Map.Entry<Integer, List<Pair<String, WrappedArgument<?>>>> entry : arguments.entrySet()) {
List<Pair<String, WrappedArgument<?>>> value = entry.getValue();
ArgumentBuilder<CommandSourceStack, ?> branchArgumentBuilder = null;
Command<CommandSourceStack> executor = context -> {
if (executor(new CommandContext(context), action)) {
return Command.SINGLE_SUCCESS;
} else {
return 0;
}
};
for (Pair<String, WrappedArgument<?>> stringWrappedArgumentPair : value.reversed()) {
WrappedArgument<?> argument = stringWrappedArgumentPair.getRight();
@@ -86,7 +86,7 @@ public class StartCommand extends LiteralNode {
}
}
if (value.getFirst().getRight().isOptional()) {
if (value.getFirst().getRight().isOptional() || value.isEmpty()) {
builder = builder.executes(executor);
}
@@ -94,6 +94,11 @@ public class StartCommand extends LiteralNode {
builder = builder.then(branchArgumentBuilder);
}
}
if (arguments.isEmpty()) {
builder = builder.executes(executor);
}
return builder;
}
};

View File

@@ -1,6 +1,7 @@
package org.leavesmc.leaves.neo_command.bot.subcommands.action;
import com.mojang.brigadier.arguments.IntegerArgumentType;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import net.minecraft.network.chat.Component;
@@ -15,6 +16,7 @@ import org.leavesmc.leaves.neo_command.LiteralNode;
import org.leavesmc.leaves.neo_command.bot.subcommands.ActionCommand;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
@@ -40,29 +42,29 @@ public class StopCommand extends LiteralNode {
}
@Override
protected CompletableFuture<Suggestions> getSuggestions(CommandContext context, SuggestionsBuilder builder) {
protected CompletableFuture<Suggestions> getSuggestions(CommandContext context, SuggestionsBuilder builder) throws CommandSyntaxException {
ServerBot bot = ActionCommand.BotArgument.getBot(context);
if (bot == null) {
return Suggestions.empty();
}
for (int i = 0; i < bot.getBotActions().size(); i++) {
ServerBotAction<?> action = bot.getBotActions().get(i);
builder.suggest(String.valueOf(i), Component.literal(action.getName()));
}
return builder.buildFuture();
}
@Override
protected boolean execute(CommandContext context) {
protected boolean execute(CommandContext context) throws CommandSyntaxException {
ServerBot bot = ActionCommand.BotArgument.getBot(context);
CommandSender sender = context.getSender();
if (bot == null) {
return false;
int index = context.getArgument(StopIndexArgument.class);
int maxIndex = bot.getBotActions().size() - 1;
if (maxIndex < 0) {
throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument().create();
}
int index = context.getArgument("index", Integer.class);
if (index < 0 || index >= bot.getBotActions().size()) {
sender.sendMessage(text("Invalid index.", RED));
return false;
if (index > maxIndex) {
throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.integerTooHigh().create(index, maxIndex);
}
ServerBotAction<?> action = bot.getBotActions().get(index);
@@ -77,7 +79,7 @@ public class StopCommand extends LiteralNode {
text("Already stopped", GRAY),
asAdventure(bot.getDisplayName()).append(text("'s", GRAY)),
text("action", GRAY),
text(action.getName(), AQUA).hoverEvent(showText(text(action.getReadableActionDataString())))
text(action.getName(), AQUA).hoverEvent(showText(text(action.getActionDataString())))
));
} else {
sender.sendMessage(text("Action stop cancelled by a plugin", RED));
@@ -93,17 +95,21 @@ public class StopCommand extends LiteralNode {
}
@Override
protected boolean execute(@NotNull CommandContext context) {
protected boolean execute(@NotNull CommandContext context) throws CommandSyntaxException {
ServerBot bot = ActionCommand.BotArgument.getBot(context);
if (bot == null) {
return false;
List<ServerBotAction<?>> actions = bot.getBotActions();
CommandSender sender = context.getSender();
if (actions.isEmpty()) {
sender.sendMessage(text("This bot has no active actions", GRAY));
return true;
}
Set<ServerBotAction<?>> canceled = new HashSet<>();
Set<ServerBotAction<?>> forRemoval = new HashSet<>();
for (int i = 0; i < bot.getBotActions().size(); i++) {
ServerBotAction<?> action = bot.getBotActions().get(i);
for (ServerBotAction<?> action : actions) {
BotActionStopEvent event = new BotActionStopEvent(
bot.getBukkitEntity(), action.getName(), action.getUUID(), BotActionStopEvent.Reason.COMMAND, context.getSender()
bot.getBukkitEntity(), action.getName(), action.getUUID(), BotActionStopEvent.Reason.COMMAND, sender
);
event.callEvent();
if (!event.isCancelled()) {
@@ -114,14 +120,21 @@ public class StopCommand extends LiteralNode {
}
}
bot.getBotActions().removeAll(forRemoval);
if (canceled.isEmpty()) {
context.getSender().sendMessage(bot.getScoreboardName() + "'s action list cleared.");
sender.sendMessage(join(spaces(),
asAdventure(bot.getDisplayName()).append(text("'s", GRAY)),
text("'s action list cleared", GRAY)
));
} else {
context.getSender().sendMessage("already tried to clear" + bot.getScoreboardName() + "'s action list, but following actions' stop was canceled by plugin:");
sender.sendMessage(join(spaces(),
text("Tried to clear", GRAY),
asAdventure(bot.getDisplayName()).append(text("'s", GRAY)),
text("'s action list, but following actions' stop was canceled by plugin:", GRAY)
));
for (ServerBotAction<?> action : canceled) {
context.getSender().sendMessage(
text(action.getName(), AQUA)
.hoverEvent(showText(text(action.getReadableActionDataString())))
text(action.getName(), AQUA).hoverEvent(showText(text(action.getActionDataString())))
);
}
}