001package co.aikar.commands; 002 003import co.aikar.commands.apachecommonslang.ApacheCommonsExceptionUtil; 004import com.google.common.collect.Maps; 005import net.dv8tion.jda.core.AccountType; 006import net.dv8tion.jda.core.JDA; 007import net.dv8tion.jda.core.entities.ChannelType; 008import net.dv8tion.jda.core.entities.Message; 009import net.dv8tion.jda.core.events.message.MessageReceivedEvent; 010import org.jetbrains.annotations.NotNull; 011 012import java.util.Arrays; 013import java.util.List; 014import java.util.Map; 015import java.util.logging.Level; 016import java.util.logging.Logger; 017 018public class JDACommandManager extends CommandManager< 019 MessageReceivedEvent, 020 JDACommandEvent, 021 String, 022 MessageFormatter<String>, 023 JDACommandExecutionContext, 024 JDAConditionContext 025 > { 026 027 private final JDA jda; 028 protected JDACommandCompletions completions; 029 protected JDACommandContexts contexts; 030 protected JDALocales locales; 031 protected Map<String, JDARootCommand> commands = Maps.newHashMap(); 032 private Logger logger; 033 private CommandConfig defaultConfig; 034 private CommandConfigProvider configProvider; 035 private CommandPermissionResolver permissionResolver; 036 private long botOwner = 0L; 037 038 public JDACommandManager(JDA jda) { 039 this(jda, null); 040 } 041 042 public JDACommandManager(JDA jda, JDAOptions options) { 043 if (options == null) { 044 options = new JDAOptions(); 045 } 046 this.jda = jda; 047 this.permissionResolver = options.permissionResolver; 048 jda.addEventListener(new JDAListener(this)); 049 this.defaultConfig = options.defaultConfig == null ? new JDACommandConfig() : options.defaultConfig; 050 this.configProvider = options.configProvider; 051 this.completions = new JDACommandCompletions(this); 052 this.logger = Logger.getLogger(this.getClass().getSimpleName()); 053 054 getCommandConditions().addCondition("owneronly", context -> { 055 if (context.getIssuer().getEvent().getAuthor().getIdLong() != getBotOwnerId()) { 056 throw new ConditionFailedException("Only the bot owner can use this command."); // TODO: MessageKey 057 } 058 }); 059 060 getCommandConditions().addCondition("guildonly", context -> { 061 if (context.getIssuer().getEvent().getChannelType() != ChannelType.TEXT) { 062 throw new ConditionFailedException("This command must be used in guild chat."); // TODO: MessageKey 063 } 064 }); 065 066 getCommandConditions().addCondition("privateonly", context -> { 067 if (context.getIssuer().getEvent().getChannelType() != ChannelType.PRIVATE) { 068 throw new ConditionFailedException("This command must be used in private chat."); // TODO: MessageKey 069 } 070 }); 071 072 getCommandConditions().addCondition("grouponly", context -> { 073 if (context.getIssuer().getEvent().getChannelType() != ChannelType.GROUP) { 074 throw new ConditionFailedException("This command must be used in group chat."); // TODO: MessageKey 075 } 076 }); 077 } 078 079 public static JDAOptions options() { 080 return new JDAOptions(); 081 } 082 083 void initializeBotOwner() { 084 if (botOwner == 0L) { 085 if (jda.getAccountType() == AccountType.BOT) { 086 botOwner = jda.asBot().getApplicationInfo().complete().getOwner().getIdLong(); 087 } else { 088 botOwner = jda.getSelfUser().getIdLong(); 089 } 090 } 091 } 092 093 private long getBotOwnerId() { 094 // Just in case initialization on ReadyEvent fails. 095 initializeBotOwner(); 096 return botOwner; 097 } 098 099 public JDA getJDA() { 100 return jda; 101 } 102 103 public Logger getLogger() { 104 return logger; 105 } 106 107 public void setLogger(Logger logger) { 108 this.logger = logger; 109 } 110 111 public CommandConfig getDefaultConfig() { 112 return defaultConfig; 113 } 114 115 public void setDefaultConfig(@NotNull CommandConfig defaultConfig) { 116 this.defaultConfig = defaultConfig; 117 } 118 119 public CommandConfigProvider getConfigProvider() { 120 return configProvider; 121 } 122 123 public void setConfigProvider(CommandConfigProvider configProvider) { 124 this.configProvider = configProvider; 125 } 126 127 public CommandPermissionResolver getPermissionResolver() { 128 return permissionResolver; 129 } 130 131 public void setPermissionResolver(CommandPermissionResolver permissionResolver) { 132 this.permissionResolver = permissionResolver; 133 } 134 135 @Override 136 public CommandContexts<?> getCommandContexts() { 137 if (this.contexts == null) { 138 this.contexts = new JDACommandContexts(this); 139 } 140 return this.contexts; 141 } 142 143 @Override 144 public CommandCompletions<?> getCommandCompletions() { 145 return this.completions; 146 } 147 148 @Override 149 public void registerCommand(BaseCommand command) { 150 command.onRegister(this); 151 for (Map.Entry<String, RootCommand> entry : command.registeredCommands.entrySet()) { 152 String commandName = entry.getKey().toLowerCase(); 153 JDARootCommand cmd = (JDARootCommand) entry.getValue(); 154 if (!cmd.isRegistered) { 155 cmd.isRegistered = true; 156 commands.put(commandName, cmd); 157 } 158 } 159 } 160 161 @Override 162 public boolean hasRegisteredCommands() { 163 return !this.commands.isEmpty(); 164 } 165 166 @Override 167 public boolean isCommandIssuer(Class<?> type) { 168 return JDACommandEvent.class.isAssignableFrom(type); 169 } 170 171 @Override 172 public JDACommandEvent getCommandIssuer(Object issuer) { 173 if (!(issuer instanceof MessageReceivedEvent)) { 174 throw new IllegalArgumentException(issuer.getClass().getName() + " is not a Message Received Event."); 175 } 176 return new JDACommandEvent(this, (MessageReceivedEvent) issuer); 177 } 178 179 @Override 180 public RootCommand createRootCommand(String cmd) { 181 return new JDARootCommand(this, cmd); 182 } 183 184 @Override 185 public Locales getLocales() { 186 if (this.locales == null) { 187 this.locales = new JDALocales(this); 188 this.locales.loadLanguages(); 189 } 190 return this.locales; 191 } 192 193 @Override 194 public CommandExecutionContext createCommandContext(RegisteredCommand command, CommandParameter parameter, CommandIssuer sender, List<String> args, int i, Map<String, Object> passedArgs) { 195 return new JDACommandExecutionContext(command, parameter, (JDACommandEvent) sender, args, i, passedArgs); 196 } 197 198 @Override 199 public CommandCompletionContext createCompletionContext(RegisteredCommand command, CommandIssuer sender, String input, String config, String[] args) { 200 // Not really going to be used; 201 //noinspection unchecked 202 return new CommandCompletionContext(command, sender, input, config, args); 203 } 204 205 @Override 206 public void log(LogLevel level, String message, Throwable throwable) { 207 Level logLevel = level == LogLevel.INFO ? Level.INFO : Level.SEVERE; 208 logger.log(logLevel, LogLevel.LOG_PREFIX + message); 209 if (throwable != null) { 210 for (String line : ACFPatterns.NEWLINE.split(ApacheCommonsExceptionUtil.getFullStackTrace(throwable))) { 211 logger.log(logLevel, LogLevel.LOG_PREFIX + line); 212 } 213 } 214 } 215 216 void dispatchEvent(MessageReceivedEvent event) { 217 Message message = event.getMessage(); 218 String msg = message.getContentRaw(); 219 220 CommandConfig config = getCommandConfig(event); 221 222 String prefixFound = null; 223 for (String prefix : config.getCommandPrefixes()) { 224 if (msg.startsWith(prefix)) { 225 prefixFound = prefix; 226 break; 227 } 228 } 229 if (prefixFound == null) { 230 return; 231 } 232 233 String[] args = ACFPatterns.SPACE.split(msg.substring(prefixFound.length()), -1); 234 if (args.length == 0) { 235 return; 236 } 237 String cmd = args[0].toLowerCase(); 238 JDARootCommand rootCommand = this.commands.get(cmd); 239 if (rootCommand == null) { 240 return; 241 } 242 if (args.length > 1) { 243 args = Arrays.copyOfRange(args, 1, args.length); 244 } else { 245 args = new String[0]; 246 } 247 rootCommand.execute(this.getCommandIssuer(event), cmd, args); 248 } 249 250 private CommandConfig getCommandConfig(MessageReceivedEvent event) { 251 CommandConfig config = this.defaultConfig; 252 if (this.configProvider != null) { 253 CommandConfig provided = this.configProvider.provide(event); 254 if (provided != null) { 255 config = provided; 256 } 257 } 258 return config; 259 } 260 261 262 @Override 263 public String getCommandPrefix(CommandIssuer issuer) { 264 MessageReceivedEvent event = ((JDACommandEvent) issuer).getEvent(); 265 CommandConfig commandConfig = getCommandConfig(event); 266 List<String> prefixes = commandConfig.getCommandPrefixes(); 267 return prefixes.isEmpty() ? "" : prefixes.get(0); 268 } 269}