Skip to content

Commit

Permalink
Merge pull request #25 from okocraft/brigadier-commands
Browse files Browse the repository at this point in the history
Reimplement commands using brigadier
  • Loading branch information
Siroshun09 authored Jun 6, 2024
2 parents f2b6eae + 640fa15 commit f0cb81e
Show file tree
Hide file tree
Showing 14 changed files with 254 additions and 450 deletions.
6 changes: 0 additions & 6 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,6 @@
<version>4.6.4</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.github.siroshun09.mccommand</groupId>
<artifactId>paper</artifactId>
<version>3.0.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.github.siroshun09.translationloader</groupId>
<artifactId>translationloader</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@
import com.github.siroshun09.configapi.api.Configuration;
import com.github.siroshun09.configapi.api.util.ResourceUtils;
import com.github.siroshun09.configapi.yaml.YamlConfiguration;
import com.github.siroshun09.mccommand.paper.PaperCommandFactory;
import com.github.siroshun09.mccommand.paper.listener.AsyncTabCompleteListener;
import com.github.siroshun09.translationloader.ConfigurationLoader;
import com.github.siroshun09.translationloader.TranslationLoader;
import com.github.siroshun09.translationloader.directory.TranslationDirectory;
import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents;
import net.kyori.adventure.key.Key;
import net.okocraft.armorstandeditor.command.ArmorStandEditorCommand;
import net.okocraft.armorstandeditor.item.EditToolItem;
Expand All @@ -25,7 +24,6 @@
import java.io.IOException;
import java.nio.file.Path;
import java.util.Locale;
import java.util.Optional;
import java.util.jar.JarFile;
import java.util.logging.Level;

Expand Down Expand Up @@ -70,15 +68,8 @@ public void onEnable() {
manager.registerEvents(new InventoryListener(), this);
manager.registerEvents(new PlayerListener(this), this);

var command = new ArmorStandEditorCommand(this);

Optional.ofNullable(getCommand("armorstandeditor"))
.ifPresent(target -> {
PaperCommandFactory.register(target, command);
AsyncTabCompleteListener.register(this, command);
});

editToolItem = new EditToolItem(this);
this.editToolItem = new EditToolItem(this);
this.getLifecycleManager().registerEventHandler(LifecycleEvents.COMMANDS, event -> ArmorStandEditorCommand.register(event.registrar(), this));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,95 +1,173 @@
package net.okocraft.armorstandeditor.command;

import com.github.siroshun09.mccommand.common.AbstractCommand;
import com.github.siroshun09.mccommand.common.Command;
import com.github.siroshun09.mccommand.common.CommandResult;
import com.github.siroshun09.mccommand.common.SubCommandHolder;
import com.github.siroshun09.mccommand.common.context.CommandContext;
import com.github.siroshun09.mccommand.common.filter.StringFilter;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import io.papermc.paper.command.brigadier.CommandSourceStack;
import io.papermc.paper.command.brigadier.Commands;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.okocraft.armorstandeditor.ArmorStandEditorPlugin;
import net.okocraft.armorstandeditor.command.subcommand.AxisCommand;
import net.okocraft.armorstandeditor.command.subcommand.EquipmentCommand;
import net.okocraft.armorstandeditor.command.subcommand.ItemCommand;
import net.okocraft.armorstandeditor.command.subcommand.ModeCommand;
import net.okocraft.armorstandeditor.command.subcommand.ReloadCommand;
import net.okocraft.armorstandeditor.editor.EditMode;
import net.okocraft.armorstandeditor.editor.PlayerEditor;
import net.okocraft.armorstandeditor.editor.PlayerEditorProvider;
import net.okocraft.armorstandeditor.item.EditToolItem;
import net.okocraft.armorstandeditor.lang.Components;
import net.okocraft.armorstandeditor.lang.Messages;
import net.okocraft.armorstandeditor.menu.EquipmentMenuProvider;
import net.okocraft.armorstandeditor.permission.Permissions;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;

import java.util.Collections;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Set;

public class ArmorStandEditorCommand extends AbstractCommand {

private final SubCommandHolder holder;

public ArmorStandEditorCommand(@NotNull ArmorStandEditorPlugin plugin) {
super("armorstandeditor", Permissions.COMMAND, Set.of("ase", "aseditor"));

holder = SubCommandHolder.of(
new AxisCommand(),
new EquipmentCommand(),
new ItemCommand(plugin),
new ModeCommand(),
new ReloadCommand(plugin)
import java.util.Locale;

@SuppressWarnings("UnstableApiUsage")
public final class ArmorStandEditorCommand {

public static void register(Commands commands, ArmorStandEditorPlugin plugin) {
commands.register(
plugin.getPluginMeta(),
Commands.literal("armorstandeditor")
.requires(source -> source.getSender().hasPermission(Permissions.COMMAND))
.executes(ctx -> {
ctx.getSource().getSender().sendMessage(Messages.COMMAND_ARGUMENT_NOT_ENOUGH);
return Command.SINGLE_SUCCESS;
})
.then(axis())
.then(equipment())
.then(item(plugin.getEditToolItem()))
.then(mode())
.then(reload(plugin))
.build(),
"The root command of ArmorStandEditor",
List.of("ase", "aseditor")
);
}

@Override
public @NotNull CommandResult onExecution(@NotNull CommandContext context) {
var sender = context.getSender();

if (!sender.hasPermission(getPermission())) {
sender.sendMessage(Messages.COMMAND_NO_PERMISSION);
return CommandResult.NO_PERMISSION;
}

var arguments = context.getArguments();

if (arguments.isEmpty()) {
sender.sendMessage(Messages.COMMAND_ARGUMENT_NOT_ENOUGH);
return CommandResult.NO_ARGUMENT;
}

var sub = holder.search(arguments.get(0));

if (sub != null) {
return sub.onExecution(context);
} else {
sender.sendMessage(Messages.COMMAND_SUB_COMMAND_NOT_FOUND);
return CommandResult.INVALID_ARGUMENTS;
}
public static LiteralArgumentBuilder<CommandSourceStack> axis() {
return Commands.literal("axis")
.requires(source ->
source.getSender().hasPermission(Permissions.COMMAND_AXIS) &&
source.getSender() instanceof Player
)
.then(
Commands.argument(
"axis",
new ConstantsArgumentType<>(
Arrays.stream(PlayerEditor.Axis.values()).map(Enum::name).map(name -> name.toLowerCase(Locale.ENGLISH)).toList(),
name -> {
try {
return PlayerEditor.Axis.valueOf(name.toUpperCase(Locale.ENGLISH));
} catch (IllegalArgumentException ignored) {
return null;
}
},
argument -> Messages.COMMAND_AXIS_INVALID_ARGUMENT.append(Component.text(argument, NamedTextColor.AQUA)),
Messages.COMMAND_AXIS_TOOLTIP
)
).executes(context -> {
var axis = context.getArgument("axis", PlayerEditor.Axis.class);
PlayerEditorProvider.getEditor((Player) context.getSource().getSender()).setAxis(axis);

context.getSource().getSender().sendMessage(
Messages.COMMAND_AXIS_CHANGE.append(Components.AXIS_NAME.apply(axis))
);

return Command.SINGLE_SUCCESS;
})
);
}

@Override
public @NotNull List<String> onTabCompletion(@NotNull CommandContext context) {
if (!context.getSender().hasPermission(getPermission())) {
return Collections.emptyList();
}

var arguments = context.getArguments();

if (arguments.isEmpty()) {
return Collections.emptyList();
}
public static LiteralArgumentBuilder<CommandSourceStack> equipment() {
return Commands.literal("equipment")
.requires(source ->
source.getSender().hasPermission(Permissions.COMMAND_EQUIPMENT) &&
source.getSender() instanceof Player
)
.executes(context -> {
var player = (Player) context.getSource().getSender();
var target = player.getTargetEntity(3);

if (target instanceof ArmorStand armorStand) {
player.openInventory(EquipmentMenuProvider.getMenu(armorStand).getInventory());
} else {
player.sendMessage(Messages.COMMAND_EQUIPMENT_ARMOR_STAND_NOT_FOUND);
}

return Command.SINGLE_SUCCESS;
});
}

if (arguments.size() == 1) {
var argumentFilter = StringFilter.startsWithIgnoreCase(arguments.get(0).get());
public static LiteralArgumentBuilder<CommandSourceStack> item(@NotNull EditToolItem editToolItem) {
return Commands.literal("item")
.requires(source ->
source.getSender().hasPermission(Permissions.COMMAND_ITEM) &&
source.getSender() instanceof Player
)
.executes(context -> {
var player = (Player) context.getSource().getSender();

if (player.getInventory().addItem(editToolItem.createEditTool()).isEmpty()) {
player.sendMessage(Messages.COMMAND_ITEM_SUCCESS);
} else {
player.sendMessage(Messages.COMMAND_ITEM_FAILURE);
}

return Command.SINGLE_SUCCESS;
});
}

return holder.getSubCommands()
.stream()
.map(Command::getName)
.filter(argumentFilter)
.toList();
}
public static LiteralArgumentBuilder<CommandSourceStack> mode() {
return Commands.literal("mode")
.requires(source ->
source.getSender().hasPermission(Permissions.COMMAND_MODE) &&
source.getSender() instanceof Player
)
.then(
Commands.argument(
"mode",
new ConstantsArgumentType<>(
EditMode.names().toList(),
EditMode::byName,
argument -> Messages.COMMAND_MODE_INVALID_ARGUMENT.append(Component.text(argument, NamedTextColor.AQUA)),
Messages.COMMAND_MODE_TOOLTIP
)
).executes(context -> {
var player = (Player) context.getSource().getSender();
var mode = context.getArgument("mode", EditMode.class);

if (player.hasPermission(mode.getPermission())) {
PlayerEditorProvider.getEditor(player).setMode(mode);
player.sendMessage(Messages.COMMAND_MODE_CHANGE.append(Components.MODE_NAME.apply(mode)));
} else {
player.sendMessage(Messages.COMMAND_MODE_NO_PERMISSION);
}

return Command.SINGLE_SUCCESS;
})
);
}

var sub = holder.search(arguments.get(0));
public static LiteralArgumentBuilder<CommandSourceStack> reload(@NotNull ArmorStandEditorPlugin plugin) {
return Commands.literal("reload")
.requires(source -> source.getSender().hasPermission(Permissions.COMMAND_RELOAD))
.executes(context -> {
try {
plugin.getTranslationDirectory().load();
} catch (IOException e) {
context.getSource().getSender().sendMessage(Messages.COMMAND_RELOAD_FAILURE);
return Command.SINGLE_SUCCESS;
}

context.getSource().getSender().sendMessage(Messages.COMMAND_RELOAD_SUCCESS);
return Command.SINGLE_SUCCESS;
});
}

if (sub != null) {
return sub.onTabCompletion(context);
} else {
return Collections.emptyList();
}
private ArmorStandEditorCommand() {
throw new UnsupportedOperationException();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package net.okocraft.armorstandeditor.command;

import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import io.papermc.paper.command.brigadier.MessageComponentSerializer;
import io.papermc.paper.command.brigadier.argument.CustomArgumentType;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.NotNull;

import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;

@SuppressWarnings("UnstableApiUsage")
public final class ConstantsArgumentType<T> implements CustomArgumentType<T, String> {

private final Function<String, Component> messageForInvalidInput;
private final Function<T, Component> tooltipFunction;
private final List<String> names;
private final Function<String, T> finder;

public ConstantsArgumentType(@NotNull List<String> names, @NotNull Function<String, T> finder, @NotNull Function<String, Component> messageForInvalidInput, @NotNull Function<T, Component> tooltipFunction) {
this.names = names;
this.finder = finder;
this.messageForInvalidInput = messageForInvalidInput;
this.tooltipFunction = tooltipFunction;
}

@Override
public @NotNull ArgumentType<String> getNativeType() {
return StringArgumentType.word();
}

@Override
public @NotNull T parse(@NotNull StringReader reader) throws CommandSyntaxException {
var input = reader.readUnquotedString();
var found = this.finder.apply(input);

if (found != null) {
return found;
} else {
var message = MessageComponentSerializer.message().serialize(this.messageForInvalidInput.apply(input));
throw new CommandSyntaxException(new SimpleCommandExceptionType(message), message, reader.getString(), reader.getCursor());
}
}

@Override
public @NotNull <S> CompletableFuture<Suggestions> listSuggestions(@NotNull CommandContext<S> context, @NotNull SuggestionsBuilder builder) {
var input = builder.getRemaining();
boolean empty = input.isEmpty();

for (var name : this.names) {
if (empty || startsWith(name, input, input.length())) {
builder.suggest(name, MessageComponentSerializer.message().serialize(this.tooltipFunction.apply(this.finder.apply(name))));
}
}

return CompletableFuture.completedFuture(builder.build());
}

private static boolean startsWith(@NotNull String str, @NotNull String prefix, int prefixLength) {
return prefixLength <= str.length() && str.regionMatches(true, 0, prefix, 0, prefixLength);
}
}
Loading

0 comments on commit f0cb81e

Please sign in to comment.