Began introduction of new command system

This commit is contained in:
Auxilor
2021-07-05 15:14:54 +02:00
parent a21ecfbdde
commit b0806b934b
10 changed files with 383 additions and 2 deletions

View File

@@ -1,6 +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.config.ConfigHandler;
import com.willfp.eco.core.config.base.ConfigYml;
import com.willfp.eco.core.config.base.LangYml;
@@ -46,6 +47,7 @@ import java.util.Set;
import java.util.logging.Logger;
import java.util.stream.Collectors;
@SuppressWarnings({"deprecation", "DeprecatedIsStillUsed"})
public abstract class EcoPlugin extends JavaPlugin {
/**
* Loaded eco plugins.
@@ -394,6 +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.getScheduler().runLater(this::afterLoad, 1);
@@ -549,11 +552,22 @@ public abstract class EcoPlugin extends JavaPlugin {
}
/**
* The command to be registered.
* The commands to be registered.
*
* @return A list of commands.
* @deprecated Use {@link this#getPluginCommands()} instead.
*/
@Deprecated
public List<AbstractCommand> getCommands() {
return new ArrayList<>();
}
/**
* The commands to be registered.
*
* @return A list of commands.
*/
public List<AbstractCommand> getCommands() {
public List<BaseCommand> getPluginCommands() {
return new ArrayList<>();
}

View File

@@ -14,6 +14,8 @@ import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.List;
@Deprecated
@SuppressWarnings("DeprecatedIsStillUsed")
public abstract class AbstractCommand extends PluginDependent<EcoPlugin> implements CommandExecutor {
/**
* The name of the command

View File

@@ -9,6 +9,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.List;
@Deprecated
public abstract class AbstractTabCompleter implements TabCompleter {
/**
* The {@link AbstractCommand} that is tab-completed.

View File

@@ -0,0 +1,48 @@
package com.willfp.eco.core.command;
import org.jetbrains.annotations.NotNull;
public interface CommandBase {
/**
* Get command name.
*
* @return The name.
*/
String getName();
/**
* Get command permission.
*
* @return The permission.
*/
String getPermission();
/**
* If only players can execute the command.
*
* @return If true.
*/
boolean isPlayersOnly();
/**
* Add a subcommand to the command.
*
* @param command The subcommand.
* @return The parent command.
*/
CommandBase addSubcommand(@NotNull CommandBase command);
/**
* Get the handler.
*
* @return The handler.
*/
CommandHandler getHandler();
/**
* Get the tab completer.
*
* @return The tab completer.
*/
TabCompleteHandler getTabCompleter();
}

View File

@@ -0,0 +1,18 @@
package com.willfp.eco.core.command;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import java.util.List;
@FunctionalInterface
public interface CommandHandler {
/**
* The code to be called on execution.
*
* @param sender The sender.
* @param args The arguments.
*/
void onExecute(@NotNull CommandSender sender,
@NotNull List<String> args);
}

View File

@@ -0,0 +1,19 @@
package com.willfp.eco.core.command;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import java.util.List;
@FunctionalInterface
public interface TabCompleteHandler {
/**
* Handle Tab Completion.
*
* @param sender The sender.
* @param args The arguments.
* @return The tab completion results.
*/
List<String> tabComplete(@NotNull CommandSender sender,
@NotNull List<String> args);
}

View File

@@ -0,0 +1,134 @@
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 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 {
/**
* 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) {
super(name, permission, playersOnly);
}
/**
* Registers the command with the server,
* <p>
* Requires the command name to exist, defined in plugin.yml.
*/
public final void register() {
PluginCommand command = Bukkit.getPluginCommand(this.getName());
assert command != null;
command.setExecutor(this);
command.setTabCompleter(this);
}
/**
* Internal implementation used to clean up boilerplate.
* Used for parity with {@link CommandExecutor#onCommand(CommandSender, Command, String, String[])}.
*
* @param sender The executor of the command.
* @param command The bukkit command.
* @param label The name of the executed command.
* @param args The arguments of the command (anything after the physical command name)
* @return If the command was processed by the linked {@link EcoPlugin}
*/
@Override
public final boolean onCommand(@NotNull final CommandSender sender,
@NotNull final Command command,
@NotNull final String label,
@NotNull final String[] args) {
if (!command.getName().equalsIgnoreCase(this.getName())) {
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));
return true;
}
/**
* Internal implementation used to clean up boilerplate.
* Used for parity with {@link TabCompleter#onTabComplete(CommandSender, Command, String, String[])}.
*
* @param sender The executor of the command.
* @param command The bukkit command.
* @param label The name of the executed command.
* @param args The arguments of the command (anything after the physical command name).
* @return The list of tab-completions.
*/
@Override
public @Nullable List<String> onTabComplete(@NotNull final CommandSender sender,
@NotNull final Command command,
@NotNull final String label,
@NotNull final String[] args) {
if (!command.getName().equalsIgnoreCase(this.getName())) {
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));
}
}

View File

@@ -0,0 +1,82 @@
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

@@ -0,0 +1,30 @@
package com.willfp.eco.core.command.impl;
import com.willfp.eco.core.command.CommandBase;
import org.jetbrains.annotations.NotNull;
public abstract class Subcommand extends HandledCommand {
/**
* Create subcommand.
*
* @param name The subcommand name.
* @param permission The subcommand permission.
* @param playersOnly If the subcommand only works on players.
*/
protected Subcommand(@NotNull final String name,
@NotNull final String permission,
final boolean playersOnly) {
super(name, permission, playersOnly);
}
/**
* Create subcommand.
*
* @param name The name of the subcommand.
* @param parent The parent command.
*/
protected Subcommand(@NotNull final String name,
@NotNull final CommandBase parent) {
super(name, parent.getPermission(), parent.isPlayersOnly());
}
}

View File

@@ -0,0 +1,33 @@
package com.willfp.eco.core.command.util;
import com.willfp.eco.core.command.CommandBase;
import com.willfp.eco.internal.Internals;
import lombok.experimental.UtilityClass;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
@UtilityClass
public class CommandUtils {
/**
* Check if the sender can execute a command.
*
* @param sender The sender.
* @param command The command.
* @return If possible. Sends messages.
*/
public boolean canExecute(@NotNull final CommandSender sender,
@NotNull final CommandBase command) {
if (command.isPlayersOnly() && !(sender instanceof Player)) {
sender.sendMessage(Internals.getInstance().getPlugin().getLangYml().getMessage("not-player"));
return false;
}
if (!sender.hasPermission(command.getPermission()) && sender instanceof Player) {
sender.sendMessage(Internals.getInstance().getPlugin().getLangYml().getNoPermission());
return false;
}
return true;
}
}