Improved subcommand system

This commit is contained in:
Auxilor
2021-07-05 17:37:05 +02:00
parent d4e1f58f2a
commit 04c450b46a
5 changed files with 176 additions and 138 deletions

View File

@@ -1,7 +1,7 @@
package com.willfp.eco.core;
import com.willfp.eco.core.command.AbstractCommand;
import com.willfp.eco.core.command.impl.BaseCommand;
import com.willfp.eco.core.command.impl.PluginCommand;
import com.willfp.eco.core.config.ConfigHandler;
import com.willfp.eco.core.config.base.ConfigYml;
import com.willfp.eco.core.config.base.LangYml;
@@ -396,7 +396,7 @@ public abstract class EcoPlugin extends JavaPlugin {
this.getListeners().forEach(listener -> this.getEventManager().registerListener(listener));
this.getCommands().forEach(AbstractCommand::register);
this.getPluginCommands().forEach(BaseCommand::register);
this.getPluginCommands().forEach(PluginCommand::register);
this.getScheduler().runLater(this::afterLoad, 1);
@@ -567,7 +567,7 @@ public abstract class EcoPlugin extends JavaPlugin {
*
* @return A list of commands.
*/
public List<BaseCommand> getPluginCommands() {
public List<PluginCommand> getPluginCommands() {
return new ArrayList<>();
}

View File

@@ -1,82 +0,0 @@
package com.willfp.eco.core.command.impl;
import com.willfp.eco.core.command.CommandBase;
import com.willfp.eco.core.command.CommandHandler;
import com.willfp.eco.core.command.TabCompleteHandler;
import lombok.AccessLevel;
import lombok.Getter;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.TabCompleter;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
public abstract class HandledCommand implements CommandBase, CommandExecutor, TabCompleter {
/**
* The name of the command.
*/
@Getter
private final String name;
/**
* The permission required to execute the command.
* <p>
* Written out as a string for flexibility with subclasses.
*/
@Getter
private final String permission;
/**
* Should the command only be allowed to be executed by players?
* <p>
* In other worlds, only allowed to be executed by console.
*/
@Getter
private final boolean playersOnly;
/**
* All subcommands for the command.
*/
@Getter(AccessLevel.PROTECTED)
private final List<CommandBase> subcommands;
/**
* Create a new command.
* <p>
* The name cannot be the same as an existing command as this will conflict.
*
* @param name The name used in execution.
* @param permission The permission required to execute the command.
* @param playersOnly If only players should be able to execute this command.
*/
protected HandledCommand(@NotNull final String name,
@NotNull final String permission,
final boolean playersOnly) {
this.name = name;
this.permission = permission;
this.playersOnly = playersOnly;
this.subcommands = new ArrayList<>();
}
/**
* Add a subcommand to the command.
*
* @param subcommand The subcommand.
* @return The parent command.
*/
@Override
public final CommandBase addSubcommand(@NotNull final CommandBase subcommand) {
subcommands.add(subcommand);
return this;
}
@Override
public abstract CommandHandler getHandler();
@Override
public TabCompleteHandler getTabCompleter() {
return (sender, args) -> new ArrayList<>();
}
}

View File

@@ -1,38 +1,32 @@
package com.willfp.eco.core.command.impl;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.command.CommandBase;
import com.willfp.eco.core.command.util.CommandUtils;
import com.willfp.eco.internal.commands.HandledCommand;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.PluginCommand;
import org.bukkit.command.TabCompleter;
import org.bukkit.util.StringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
public abstract class BaseCommand extends HandledCommand implements CommandExecutor, TabCompleter {
public abstract class PluginCommand extends HandledCommand implements CommandExecutor, TabCompleter {
/**
* Create a new command.
* <p>
* The command will not be registered until {@link this#register()} is called.
* <p>
* The name cannot be the same as an existing command as this will conflict.
*
* @param name The name used in execution.
* @param permission The permission required to execute the command.
* @param playersOnly If only players should be able to execute this command.
*/
protected BaseCommand(@NotNull final String name,
@NotNull final String permission,
final boolean playersOnly) {
protected PluginCommand(@NotNull final String name,
@NotNull final String permission,
final boolean playersOnly) {
super(name, permission, playersOnly);
}
@@ -42,7 +36,7 @@ public abstract class BaseCommand extends HandledCommand implements CommandExecu
* Requires the command name to exist, defined in plugin.yml.
*/
public final void register() {
PluginCommand command = Bukkit.getPluginCommand(this.getName());
org.bukkit.command.PluginCommand command = Bukkit.getPluginCommand(this.getName());
assert command != null;
command.setExecutor(this);
command.setTabCompleter(this);
@@ -67,25 +61,7 @@ public abstract class BaseCommand extends HandledCommand implements CommandExecu
return false;
}
if (!CommandUtils.canExecute(sender, this)) {
return true;
}
if (args.length > 0) {
for (CommandBase subcommand : this.getSubcommands()) {
if (subcommand.getName().equalsIgnoreCase(args[0])) {
if (!CommandUtils.canExecute(sender, subcommand)) {
return true;
}
subcommand.getHandler().onExecute(sender, Arrays.asList(Arrays.copyOfRange(args, 1, args.length)));
return true;
}
}
}
this.getHandler().onExecute(sender, Arrays.asList(args));
this.handle(sender, args);
return true;
}
@@ -109,26 +85,6 @@ public abstract class BaseCommand extends HandledCommand implements CommandExecu
return null;
}
if (!sender.hasPermission(this.getPermission())) {
return null;
}
if (args.length > 0) {
List<String> completions = new ArrayList<>();
StringUtil.copyPartialMatches(
args[0],
this.getSubcommands().stream().map(CommandBase::getName).collect(Collectors.toList()),
completions
);
Collections.sort(completions);
if (!completions.isEmpty()) {
return completions;
}
}
return this.getTabCompleter().tabComplete(sender, Arrays.asList(args));
return this.handleTabCompletion(sender, args);
}
}

View File

@@ -1,6 +1,7 @@
package com.willfp.eco.core.command.impl;
import com.willfp.eco.core.command.CommandBase;
import com.willfp.eco.internal.commands.HandledCommand;
import org.jetbrains.annotations.NotNull;
public abstract class Subcommand extends HandledCommand {

View File

@@ -0,0 +1,163 @@
package com.willfp.eco.internal.commands;
import com.willfp.eco.core.command.CommandBase;
import com.willfp.eco.core.command.CommandHandler;
import com.willfp.eco.core.command.TabCompleteHandler;
import com.willfp.eco.core.command.util.CommandUtils;
import lombok.AccessLevel;
import lombok.Getter;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.bukkit.util.StringUtil;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
public abstract class HandledCommand implements CommandBase, CommandExecutor, TabCompleter {
/**
* The name of the command.
*/
@Getter
private final String name;
/**
* The permission required to execute the command.
* <p>
* Written out as a string for flexibility with subclasses.
*/
@Getter
private final String permission;
/**
* Should the command only be allowed to be executed by players?
* <p>
* In other worlds, only allowed to be executed by console.
*/
@Getter
private final boolean playersOnly;
/**
* All subcommands for the command.
*/
@Getter(AccessLevel.PROTECTED)
private final List<CommandBase> subcommands;
/**
* Create a new command.
* <p>
* The name cannot be the same as an existing command as this will conflict.
*
* @param name The name used in execution.
* @param permission The permission required to execute the command.
* @param playersOnly If only players should be able to execute this command.
*/
protected HandledCommand(@NotNull final String name,
@NotNull final String permission,
final boolean playersOnly) {
this.name = name;
this.permission = permission;
this.playersOnly = playersOnly;
this.subcommands = new ArrayList<>();
}
/**
* Add a subcommand to the command.
*
* @param subcommand The subcommand.
* @return The parent command.
*/
@Override
public final CommandBase addSubcommand(@NotNull final CommandBase subcommand) {
subcommands.add(subcommand);
return this;
}
/**
* Handle the command.
*
* @param sender The sender.
* @param args The arguments.
*/
protected final void handle(@NotNull final CommandSender sender,
@NotNull final String[] args) {
if (!CommandUtils.canExecute(sender, this)) {
return;
}
if (args.length > 0) {
for (CommandBase subcommand : this.getSubcommands()) {
if (subcommand.getName().equalsIgnoreCase(args[0])) {
if (!CommandUtils.canExecute(sender, subcommand)) {
return;
}
((HandledCommand) subcommand).handle(sender, Arrays.copyOfRange(args, 1, args.length));
return;
}
}
}
this.getHandler().onExecute(sender, Arrays.asList(args));
}
/**
* Handle the tab completion.
*
* @param sender The sender.
* @param args The arguments.
*/
protected final List<String> handleTabCompletion(@NotNull final CommandSender sender,
@NotNull final String[] args) {
if (!sender.hasPermission(this.getPermission())) {
return null;
}
if (args.length == 1) {
List<String> completions = new ArrayList<>();
StringUtil.copyPartialMatches(
args[0],
this.getSubcommands().stream().map(CommandBase::getName).collect(Collectors.toList()),
completions
);
Collections.sort(completions);
if (!completions.isEmpty()) {
return completions;
}
}
if (args.length >= 2) {
HandledCommand command = null;
for (CommandBase subcommand : this.getSubcommands()) {
if (args[0].equalsIgnoreCase(subcommand.getName())) {
command = (HandledCommand) subcommand;
}
}
if (command != null) {
return command.handleTabCompletion(sender, Arrays.copyOfRange(args, 1, args.length));
}
}
return this.getTabCompleter().tabComplete(sender, Arrays.asList(args));
}
@Override
public abstract CommandHandler getHandler();
@Override
public TabCompleteHandler getTabCompleter() {
return (sender, args) -> new ArrayList<>();
}
}