use of com.freya02.botcommands.internal.application.slash.SlashCommandInfo in project BotCommands by freya022.
the class ApplicationCommandsUpdater method computeSlashCommands.
private void computeSlashCommands(List<ApplicationCommandInfo> guildApplicationCommands) {
guildApplicationCommands.stream().filter(a -> a instanceof SlashCommandInfo).map(a -> (SlashCommandInfo) a).distinct().forEachOrdered(info -> {
final CommandPath notLocalizedPath = info.getPath();
try {
final LocalizedCommandData localizedCommandData = LocalizedCommandData.of(context, guild, info);
// Put localized option names in order to resolve them when called
final List<OptionData> localizedMethodOptions = getLocalizedMethodOptions(info, localizedCommandData);
if (guild != null) {
info.putLocalizedOptions(guild.getIdLong(), localizedMethodOptions.stream().map(OptionData::getName).collect(Collectors.toList()));
}
localizedBaseNameToBaseName.put(localizedCommandData.getLocalizedPath().getName(), notLocalizedPath.getName());
final CommandPath localizedPath = localizedCommandData.getLocalizedPath();
final String description = localizedCommandData.getLocalizedDescription();
Checks.check(localizedPath.getNameCount() == notLocalizedPath.getNameCount(), "Localized path does not have the same name count as the not-localized path");
final boolean isDefaultEnabled = isDefaultEnabled(info);
if (localizedPath.getNameCount() == 1) {
// Standard command
final SlashCommandData rightCommand = Commands.slash(localizedPath.getName(), description);
map.put(Command.Type.SLASH, localizedPath, rightCommand);
rightCommand.addOptions(localizedMethodOptions);
rightCommand.setDefaultEnabled(isDefaultEnabled);
} else if (localizedPath.getNameCount() == 2) {
Checks.notNull(localizedPath.getSubname(), "Subcommand name");
final SlashCommandData commandData = (SlashCommandData) map.computeIfAbsent(Command.Type.SLASH, localizedPath, x -> {
final SlashCommandData tmpData = Commands.slash(localizedPath.getName(), "No description (base name)");
tmpData.setDefaultEnabled(isDefaultEnabled);
return tmpData;
});
// Subcommand of a command
final SubcommandData subcommandData = new SubcommandData(localizedPath.getSubname(), description);
subcommandData.addOptions(localizedMethodOptions);
commandData.addSubcommands(subcommandData);
} else if (localizedPath.getNameCount() == 3) {
Checks.notNull(localizedPath.getGroup(), "Command group name");
Checks.notNull(localizedPath.getSubname(), "Subcommand name");
final SubcommandGroupData groupData = getSubcommandGroup(Command.Type.SLASH, localizedPath, x -> {
final SlashCommandData commandData = Commands.slash(localizedPath.getName(), "No description (base name)");
commandData.setDefaultEnabled(isDefaultEnabled);
return commandData;
});
final SubcommandData subcommandData = new SubcommandData(localizedPath.getSubname(), description);
subcommandData.addOptions(localizedMethodOptions);
groupData.addSubcommands(subcommandData);
} else {
throw new IllegalStateException("A slash command with more than 4 path components got registered");
}
context.addApplicationCommandAlternative(localizedPath, Command.Type.SLASH, info);
if (!info.isOwnerRequired()) {
if (ownerOnlyCommands.contains(notLocalizedPath.getName())) {
LOGGER.warn("Non owner-only command '{}' is registered as a owner-only command because of another command with the same base name '{}'", notLocalizedPath, notLocalizedPath.getName());
}
}
if (info.isOwnerRequired()) {
if (info.isGuildOnly()) {
ownerOnlyCommands.add(notLocalizedPath.getName());
} else {
LOGGER.warn("Owner-only command '{}' cannot be owner-only as it is a global command", notLocalizedPath);
}
}
} catch (Exception e) {
throw new RuntimeException("An exception occurred while processing command '" + notLocalizedPath + "' at " + Utils.formatMethodShort(info.getMethod()), e);
}
});
}
use of com.freya02.botcommands.internal.application.slash.SlashCommandInfo in project BotCommands by freya022.
the class LocalizationData method getData.
public static LocalizationData getData(BContext context, @Nullable Guild guild, @NotNull ApplicationCommandInfo info) {
final CommandPath localizedPath;
final String localizedDescription;
final List<LocalizedOption> localizedOptions;
final List<List<Command.Choice>> localizedChoices;
final Locale locale = context.getEffectiveLocale(guild);
final BResourceBundle bundle = BResourceBundle.getBundle("BotCommands", locale);
if (bundle == null) {
return null;
}
final String prefix;
if (info instanceof SlashCommandInfo) {
prefix = "slash";
} else if (info instanceof UserCommandInfo) {
prefix = "user";
} else if (info instanceof MessageCommandInfo) {
prefix = "message";
} else {
throw new IllegalArgumentException("Unknown localization prefix for class: " + info.getClass().getSimpleName());
}
final String qualifier = info.getMethod().getName();
final StringJoiner pathJoiner = new StringJoiner("/");
pathJoiner.add(tryLocalize(bundle, info.getPath().getName(), prefix, qualifier, "name"));
if (info instanceof SlashCommandInfo) {
final String notLocalizedGroup = info.getPath().getGroup();
final String notLocalizedSubname = info.getPath().getSubname();
if (notLocalizedGroup != null)
pathJoiner.add(tryLocalize(bundle, notLocalizedGroup, prefix, qualifier, "group"));
if (notLocalizedSubname != null)
pathJoiner.add(tryLocalize(bundle, notLocalizedSubname, prefix, qualifier, "subname"));
}
localizedPath = CommandPath.of(pathJoiner.toString());
if (info instanceof SlashCommandInfo) {
localizedDescription = tryLocalize(bundle, ((SlashCommandInfo) info).getDescription(), prefix, qualifier, "description");
} else
localizedDescription = null;
if (info instanceof SlashCommandInfo) {
localizedOptions = new ArrayList<>();
localizedChoices = new ArrayList<>();
final List<List<Command.Choice>> notLocalizedChoices = SlashUtils.getNotLocalizedChoices(context, guild, info);
final List<? extends ApplicationCommandParameter<?>> parameters = info.getOptionParameters();
for (int optionIndex = 0, parametersSize = parameters.size(); optionIndex < parametersSize; optionIndex++) {
ApplicationCommandParameter<?> parameter = parameters.get(optionIndex);
final ApplicationOptionData optionData = parameter.getApplicationOptionData();
final String optionName = tryLocalize(bundle, optionData.getEffectiveName(), prefix, qualifier, "options", optionIndex, "name");
final String optionDescription = tryLocalize(bundle, optionData.getEffectiveDescription(), prefix, qualifier, "options", optionIndex, "description");
localizedOptions.add(new LocalizedOption(optionName, optionDescription));
final List<Command.Choice> choices = getLocalizedChoices(bundle, prefix, qualifier, notLocalizedChoices, optionIndex, parameter);
localizedChoices.add(choices);
}
} else {
localizedOptions = null;
localizedChoices = null;
}
return new LocalizationData(localizedPath, localizedDescription, localizedOptions, localizedChoices);
}
use of com.freya02.botcommands.internal.application.slash.SlashCommandInfo in project BotCommands by freya022.
the class BContextImpl method addSlashCommand.
public void addSlashCommand(SlashCommandInfo commandInfo) {
final CommandPath path = commandInfo.getPath();
final Map<CommandPath, SlashCommandInfo> slashCommandMap = getSlashCommandsMap();
// Would be more performant if we used a Trie
for (Map.Entry<CommandPath, SlashCommandInfo> entry : slashCommandMap.entrySet()) {
final CommandPath commandPath = entry.getKey();
final SlashCommandInfo mapInfo = entry.getValue();
if (commandPath.getNameCount() > path.getNameCount() && commandPath.startsWith(path)) {
throw new IllegalStateException(String.format("Tried to add a command with path '%s' (at %s) but a equal/longer path already exists: '%s' (at %s)", path, Utils.formatMethodShort(commandInfo.getMethod()), commandPath, Utils.formatMethodShort(mapInfo.getMethod())));
}
}
CommandPath p = path;
do {
final SlashCommandInfo mapInfo = slashCommandMap.get(p);
if (mapInfo != null) {
throw new IllegalStateException(String.format("Tried to add a command with path '%s' (at %s) but a equal/shorter path already exists: '%s' (at %s)", path, Utils.formatMethodShort(commandInfo.getMethod()), p, Utils.formatMethodShort(mapInfo.getMethod())));
}
} while ((p = p.getParent()) != null);
slashCommandMap.put(path, commandInfo);
}
use of com.freya02.botcommands.internal.application.slash.SlashCommandInfo in project BotCommands by freya022.
the class AutocompletionHandlersBuilder method postProcess.
public void postProcess() {
for (SlashCommandInfo info : context.getApplicationCommandInfoMap().getSlashCommands().values()) {
MethodParameters<SlashCommandParameter> parameters = info.getParameters();
for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) {
SlashCommandParameter parameter = parameters.get(i);
if (!parameter.isOption())
continue;
final ApplicationOptionData applicationOptionData = parameter.getApplicationOptionData();
final String autocompleteHandlerName = applicationOptionData.getAutocompletionHandlerName();
if (autocompleteHandlerName != null) {
final AutocompletionHandlerInfo handler = context.getAutocompletionHandler(autocompleteHandlerName);
if (handler == null) {
throw new IllegalArgumentException("Slash command parameter #" + i + " at " + Utils.formatMethodShort(info.getMethod()) + " uses autocompletion but has no handler assigned, did you misspell the handler name ? Consider using a constant variable to share with the handler and the option");
}
handler.checkParameters(info);
}
}
}
context.addEventListeners(new AutocompletionListener(context));
}
use of com.freya02.botcommands.internal.application.slash.SlashCommandInfo in project BotCommands by freya022.
the class ApplicationCommandsBuilder method processSlashCommand.
private void processSlashCommand(ApplicationCommand applicationCommand, Method method) {
if (method.getAnnotation(JDASlashCommand.class).guildOnly()) {
if (!ReflectionUtils.hasFirstParameter(method, GlobalSlashEvent.class) && !ReflectionUtils.hasFirstParameter(method, GuildSlashEvent.class))
throw new IllegalArgumentException("Slash command at " + Utils.formatMethodShort(method) + " must have a GuildSlashEvent or GlobalSlashEvent as first parameter");
if (!ReflectionUtils.hasFirstParameter(method, GuildSlashEvent.class)) {
// If type is correct but guild specialization isn't used
LOGGER.warn("Guild-only slash command {} uses GlobalSlashEvent, consider using GuildSlashEvent to remove warnings related to guild stuff's nullability", Utils.formatMethodShort(method));
}
} else {
if (!ReflectionUtils.hasFirstParameter(method, GlobalSlashEvent.class))
throw new IllegalArgumentException("Slash command at " + Utils.formatMethodShort(method) + " must have a GlobalSlashEvent as first parameter");
}
final SlashCommandInfo info = new SlashCommandInfo(context, applicationCommand, method);
LOGGER.debug("Adding slash command path {} for method {}", info.getPath(), Utils.formatMethodShort(method));
context.addSlashCommand(info);
}
Aggregations