package fr.Alphart.BAT.Modules; import static fr.Alphart.BAT.I18n.I18n._; import static fr.Alphart.BAT.I18n.I18n.__; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.MissingResourceException; import java.util.regex.Matcher; import java.util.regex.Pattern; import lombok.Setter; import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.CommandSender; import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.plugin.TabExecutor; import com.google.common.base.Joiner; import com.google.common.base.Preconditions; import com.imaginarycode.minecraft.redisbungee.RedisBungee; import fr.Alphart.BAT.BAT; import fr.Alphart.BAT.Modules.Core.CommandQueue; import fr.Alphart.BAT.Modules.Core.Core; import fr.Alphart.BAT.Modules.Core.CoreCommand; import fr.Alphart.BAT.Utils.UUIDNotFoundException; public abstract class BATCommand extends net.md_5.bungee.api.plugin.Command implements TabExecutor { private static final Pattern pattern = Pattern.compile("<.*?>"); private final String name; private final String syntax; private final String description; private final String permission; private boolean runAsync = false; private boolean coreCommand = false; @Setter private int minArgs = 0; /** * Constructor * * @param name * name of this command * @param description * description of this command * @param permission * permission required to use this commands * @param aliases * aliases of this commnad (optionnal) */ public BATCommand(final String name, final String syntax, final String description, final String permission, final String... aliases) { super(name, null, aliases); // Use own permission system this.name = name; this.syntax = syntax; this.permission = permission; this.description = description; // Compute min args final Matcher matcher = pattern.matcher(syntax); while (matcher.find()) { minArgs++; } final RunAsync asyncAnnot = getClass().getAnnotation(RunAsync.class); if (asyncAnnot != null) { runAsync = true; } if(CoreCommand.class.equals(getClass().getEnclosingClass())){ coreCommand = true; } } public String getDescription() { return description; } public String getUsage() { final String usage = Joiner.on(' ').join(name, syntax, description); return usage; } public String getSyntax(){ return syntax; } /** * Get a nice coloured usage * * @return coloured usage */ public String getFormatUsage() { return ChatColor.translateAlternateColorCodes('&', "&e" + name + " &6" + syntax + " &f-&B " + description); } public String getBATPermission(){ return permission; } public void handleCommandException(final CommandSender sender, final Exception exception){ if(exception instanceof IllegalArgumentException){ if (exception.getMessage() == null) { if(coreCommand){ // Just need to add the /bat if it's a core command sender.sendMessage(__("invalidArgsUsage", new String[] { "&e/bat " + getFormatUsage() })); }else{ sender.sendMessage(__("invalidArgsUsage", new String[] { "&e/" + getFormatUsage() })); } } else if (_("noPerm").equals(exception.getMessage())) { sender.sendMessage(__("noPerm")); } else { sender.sendMessage(__("invalidArgs", new String[] { exception.getMessage() })); } } else if(exception instanceof UUIDNotFoundException){ sender.sendMessage(__("invalidArgs", new String[] { _("cannotGetUUID", new String[] { ((UUIDNotFoundException)exception).getInvolvedPlayer() }) })); } else if(exception instanceof MissingResourceException){ sender.sendMessage(BAT.__("&cAn error occured with the translation. Key involved : &a" + ((MissingResourceException)exception).getKey())); }else{ sender.sendMessage(BAT.__("A command errror happens ! Please check the console.")); BAT.getInstance().getLogger().severe("A command errror happens ! Please report this stacktrace :"); exception.printStackTrace(); } } @Override public void execute(final CommandSender sender, final String[] args) { // If the sender doesn't have the permission, we're gonna check if he has this permission with children permission // Example : in this plugin, if the sender has "bat.ban.server1", he also has "bat.ban" if(!(permission == null || sender.hasPermission(permission) || sender.hasPermission("bat.admin") || (sender.hasPermission("bat.grantall.global") && permission.endsWith("global")))){ boolean hasPerm = false; Collection<String> senderPerm = Core.getCommandSenderPermission(sender); for(final String perm : senderPerm){ // The grantall give acces to all command (used when command is executed, but the plugin check in the command if the sender can execute this action) // except the /bat ... commands if(perm.toLowerCase().startsWith(permission)){ hasPerm = true; break; } // The global grantall perm has already been checked before if (!coreCommand && perm.toLowerCase().startsWith("bat.grantall") && !permission.endsWith("global")) { // We're going to check if there is no perm to cancel (using -) final String searchedPattern = "-" + permission; boolean permFound = false; for(final String perm2 : senderPerm){ if(perm2.toLowerCase().startsWith(searchedPattern)){ permFound = true; break; } } if(permFound){ hasPerm = false; } else{ hasPerm = true; break; } } } if(!hasPerm){ sender.sendMessage(__("noPerm")); return; } } // Overrides command to confirm if /bat confirm is disabled final boolean confirmedCmd = (BAT.getInstance().getConfiguration().isConfirmCommand()) ? CommandQueue.isExecutingQueueCommand(sender) : true; try { Preconditions.checkArgument(args.length >= minArgs); if (runAsync) { ProxyServer.getInstance().getScheduler().runAsync(BAT.getInstance(), new Runnable() { @Override public void run() { try { onCommand(sender, args, confirmedCmd); } catch (final Exception exception) { handleCommandException(sender, exception); } } }); } else { onCommand(sender, args, confirmedCmd); } } catch (final Exception exception) { handleCommandException(sender, exception); } if (confirmedCmd) { CommandQueue.removeFromExecutingQueueCommand(sender); } } @Override public Iterable<String> onTabComplete(final CommandSender sender, final String[] args) { final List<String> result = new ArrayList<String>(); if (args.length == 0) { sender.sendMessage(BAT.__("Add the first letter to autocomplete")); return result; } final String playerToCheck = args[args.length - 1]; if (playerToCheck.length() > 0) { if (BAT.getInstance().getRedis().isRedisEnabled()) { for (final String player : RedisBungee.getApi().getHumanPlayersOnline()) { if (player .substring( 0, (playerToCheck.length() < player.length()) ? playerToCheck.length() : player .length()).equalsIgnoreCase(playerToCheck)) { result.add(player); } } } else { for (final ProxiedPlayer player : ProxyServer.getInstance().getPlayers()) { if (player .getName() .substring( 0, (playerToCheck.length() < player.getName().length()) ? playerToCheck.length() : player .getName().length()).equalsIgnoreCase(playerToCheck)) { result.add(player.getName()); } } } } return result; } public abstract void onCommand(final CommandSender sender, final String[] args, final boolean confirmedCmd) throws IllegalArgumentException; /** * Use this annotation onCommand if the command need to be runned async */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface RunAsync { } /** * Use this annotation to disable a command */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Disable { } /* Utils for command */ /** * Check if the sender is a player <br> * Use for readibility * * @param sender * @return true if the sender is a player otherwise false */ public boolean isPlayer(final CommandSender sender) { if (sender instanceof ProxiedPlayer) { return true; } return false; } public void mustConfirmCommand(final CommandSender sender, final String command, final String message) { final String cmdToConfirm = (BAT.getInstance().getConfiguration().getSimpleAliasesCommands().get("confirm")) ? "confirm" : "bat confirm"; if (!CommandQueue.isExecutingQueueCommand(sender)) { if ("".equals(message)) { sender.sendMessage(__("mustConfirm", new String[] { "", cmdToConfirm })); } else { sender.sendMessage(__("mustConfirm", new String[] { "&e"+message, cmdToConfirm })); } CommandQueue.queueCommand(sender, command); } } }