-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #25 from okocraft/brigadier-commands
Reimplement commands using brigadier
- Loading branch information
Showing
14 changed files
with
254 additions
and
450 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
230 changes: 154 additions & 76 deletions
230
src/main/java/net/okocraft/armorstandeditor/command/ArmorStandEditorCommand.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
} | ||
} |
70 changes: 70 additions & 0 deletions
70
src/main/java/net/okocraft/armorstandeditor/command/ConstantsArgumentType.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} |
Oops, something went wrong.