Add API for shop command and sub commands

This commit is contained in:
Eric 2019-08-17 21:34:09 +02:00
parent 5ddda4cce5
commit 57b685ecb9
3 changed files with 260 additions and 0 deletions

View File

@ -3,6 +3,7 @@ package de.epiceric.shopchest.api;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import de.epiceric.shopchest.api.command.ShopCommand;
import de.epiceric.shopchest.api.player.ShopPlayer;
/**
@ -34,4 +35,11 @@ public abstract class ShopChest extends JavaPlugin {
* @return the formatted amount
*/
public abstract String formatEconomy(double amount);
/**
* Gets the main command of this plugin
*
* @return the shop command
*/
public abstract ShopCommand getShopCommand();
}

View File

@ -0,0 +1,138 @@
package de.epiceric.shopchest.api.command;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.stream.Collectors;
import org.bukkit.command.CommandSender;
/**
* Represents the plugin's main command
*
* @since 1.13
*/
public abstract class ShopCommand {
private List<SubCommand> subCommands = new ArrayList<>();
/**
* Gets the command's name
*
* @return the name
* @since 1.13
*/
public abstract String getName();
/**
* Adds a sub command to this command
*
* @param subCommand the sub command
* @return {@code true} if the sub command has been registered, {@code false} if
* the name has already been taken
* @since 1.13
*/
public final boolean addSubCommand(SubCommand subCommand) {
boolean nameTaken = subCommands.stream().filter(sub -> sub.getName().equalsIgnoreCase(subCommand.getName()))
.findAny().isPresent();
if (nameTaken) {
return false;
}
this.subCommands.add(subCommand);
return true;
}
/**
* Removes a sub command from this command
*
* @param subCommand the sub command
* @since 1.13
*/
public final void removeSubCommand(SubCommand subCommand) {
this.subCommands.remove(subCommand);
}
/**
* Called when this command is executed
* <p>
* Sub commands are handled here and their respective {@code onExecute} method
* is called from here.
* <p>
* The first argument {@code args[0]} is the name of the sub command (if
* entered).
*
* @param sender the command sender
* @param args the arguments
* @since 1.13
*/
public final void onExecute(CommandSender sender, String... args) {
if (args.length > 0) {
Optional<SubCommand> optional = subCommands.stream()
.filter(sub -> sub.canExecute(sender) && sub.isPermitted(sender))
.filter(sub -> sub.getName().equalsIgnoreCase(args[0])).findAny();
if (!optional.isPresent()) {
sendUsage(sender);
return;
}
optional.ifPresent(sub -> {
if (args.length > 1) {
sub.onExecute(sender, Arrays.copyOfRange(args, 1, args.length));
} else {
sub.onExecute(sender);
}
});
} else {
sendUsage(sender);
}
}
/**
* Called when a sender tab completes an argument in this command
* <p>
* Only tab completion for the name of the sub command is handled here.
* Everything else has to be implemented in the sub commands respective
* {@code onTabComplete} method.
* <p>
* The first argument {@code args[0]} is the name of the sub command (if
* entered).
*
* @param sender the command sender
* @param args the arguments
* @return the tab completions
* @since 1.13
*/
public final List<String> onTabComplete(CommandSender sender, String... args) {
if (args.length == 1) {
return subCommands.stream()
.filter(sub -> sub.canExecute(sender) && sub.isPermitted(sender))
.filter(sub -> sub.getName().toLowerCase(Locale.US).startsWith(args[0].toLowerCase(Locale.US)))
.map(SubCommand::getName).collect(Collectors.toList());
} else if (args.length > 1) {
return subCommands.stream()
.filter(sub -> sub.canExecute(sender) && sub.isPermitted(sender))
.filter(sub -> sub.getName().equalsIgnoreCase(args[0])).findAny()
.map(sub -> sub.onTabComplete(sender, args))
.orElse(new ArrayList<>());
}
return new ArrayList<>();
}
/**
* Sends the help messages for all sub commands to the given sender
*
* @param sender the command sender
* @since 1.13
*/
public void sendUsage(CommandSender sender) {
String format = "[green] /%s %s [white] - [yellow] %s"; // TODO: i18n
subCommands.stream().filter(sub -> sub.canExecute(sender) && sub.isPermitted(sender))
.forEach(sub -> sender.sendMessage(String.format(format, sub.getName(), sub.getDescription())));
}
}

View File

@ -0,0 +1,114 @@
package de.epiceric.shopchest.api.command;
import java.util.List;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
/**
* Represents a sub command for the plugin's main command
*
* @see ShopCommand#addSubCommand(SubCommand)
* @since 1.13
*/
public abstract class SubCommand {
private final String name;
private final boolean onlyPlayer;
/**
* Creates a sub command with the given name
* <p>
* The sub command has to be added to the main command via
* {@link ShopCommand#addSubCommand(SubCommand)}.
*
* @param name the name
* @param onlyPlayer whether only players can run this sub command
* @see ShopCommand#addSubCommand(SubCommand)
* @since 1.13
*/
public SubCommand(String name, boolean onlyPlayer) {
this.name = name;
this.onlyPlayer = onlyPlayer;
}
/**
* Gets the name of this sub command
*
* @return the name
* @since 1.13
*/
public String getName() {
return name;
}
/**
* Gets the permission the command sender needs to run this sub command
* <p>
* If no permission is needed, this should return an empty string.
*
* @return the permission or an empty string
* @since 1.13
*/
public String getPermission() {
return "";
}
/**
* Gets whether the given sender is permitted to run this sub command
*
* @param sender the sender
* @return whether the sender is permitted
*/
public boolean isPermitted(CommandSender sender) {
return getPermission() == null || getPermission().isEmpty() || sender.hasPermission(getPermission());
}
/**
* Gets whether the given sender can run this sub command
* <p>
* This checks whether the sender is a player if the command can only be run by
* players. This does not check for permission.
*
* @param sender the sender
* @return whether the sender can run this sub command
* @since 1.13
*/
public boolean canExecute(CommandSender sender) {
return sender instanceof Player || !onlyPlayer;
}
/**
* Gets the description of this sub command
*
* @return the description
* @since 1.13
*/
public abstract String getDescription();
/**
* Called when this sub command is executed
* <p>
* The first argument {@code args[0]} is not the sub command itself, but the
* argument after it (if entered)..
*
* @param sender the sender
* @param args the arguments of the sub command
* @since 1.13
*/
public abstract void onExecute(CommandSender sender, String... args);
/**
* Called when a sender tab completes an argument in this sub command
* <p>
* The tab completion for the sub command itself is already handled. The first
* argument {@code args[0]} is not the sub command itself, but the argument
* after it (if entered)..
*
* @param sender the command sender
* @param args the arguments of the sub command
* @return the tab completions
* @since 1.13
*/
public abstract List<String> onTabComplete(CommandSender sender, String... args);
}