Execute command initial

This commit is contained in:
Vankka 2023-06-09 00:36:39 +03:00
parent 05949fe6b0
commit c32a2ad8bd
No known key found for this signature in database
GPG Key ID: 6E50CB7A29B96AD0
16 changed files with 285 additions and 119 deletions

View File

@ -27,7 +27,7 @@ import com.discordsrv.api.discord.entity.DiscordUser;
import com.discordsrv.api.discord.entity.channel.*;
import com.discordsrv.api.discord.entity.guild.DiscordGuild;
import com.discordsrv.api.discord.entity.guild.DiscordRole;
import com.discordsrv.api.discord.entity.interaction.command.Command;
import com.discordsrv.api.discord.entity.interaction.command.DiscordCommand;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -139,11 +139,11 @@ public interface DiscordAPI {
* Registers a Discord command.
* @param command the command to register
*/
Command.RegistrationResult registerCommand(Command command);
DiscordCommand.RegistrationResult registerCommand(DiscordCommand command);
/**
* Unregisters a Discord command.
* @param command the command to unregister
*/
void unregisterCommand(Command command);
void unregisterCommand(DiscordCommand command);
}

View File

@ -40,7 +40,7 @@ import java.util.regex.Pattern;
/**
* A Discord command.
*/
public class Command implements JDAEntity<CommandData> {
public class DiscordCommand implements JDAEntity<CommandData> {
private static final String CHAT_INPUT_NAME_REGEX = "(?U)[\\w-]{1,32}";
public static final Pattern CHAT_INPUT_NAME_PATTERN = Pattern.compile(CHAT_INPUT_NAME_REGEX);
@ -100,27 +100,27 @@ public class Command implements JDAEntity<CommandData> {
private final Map<Locale, String> nameTranslations;
private final Map<Locale, String> descriptionTranslations;
private final List<SubCommandGroup> subCommandGroups;
private final List<Command> subCommands;
private final List<DiscordCommand> subCommands;
private final List<CommandOption> options;
private final Long guildId;
private final boolean guildOnly;
private final DefaultPermission defaultPermission;
private final Consumer<? extends AbstractCommandInteractionEvent<?>> eventHandler;
private final Consumer<DiscordCommandAutoCompleteInteractionEvent> autoCompleteHandler;
private final AutoCompleteHandler autoCompleteHandler;
private Command(
private DiscordCommand(
ComponentIdentifier id,
CommandType type,
Map<Locale, String> nameTranslations,
Map<Locale, String> descriptionTranslations,
List<SubCommandGroup> subCommandGroups,
List<Command> subCommands,
List<DiscordCommand> subCommands,
List<CommandOption> options,
Long guildId,
boolean guildOnly,
DefaultPermission defaultPermission,
Consumer<? extends AbstractCommandInteractionEvent<?>> eventHandler,
Consumer<DiscordCommandAutoCompleteInteractionEvent> autoCompleteHandler
AutoCompleteHandler autoCompleteHandler
) {
this.id = id;
this.type = type;
@ -181,7 +181,7 @@ public class Command implements JDAEntity<CommandData> {
@NotNull
@Unmodifiable
public List<Command> getSubCommands() {
public List<DiscordCommand> getSubCommands() {
return Collections.unmodifiableList(subCommands);
}
@ -211,7 +211,7 @@ public class Command implements JDAEntity<CommandData> {
}
@Nullable
public Consumer<DiscordCommandAutoCompleteInteractionEvent> getAutoCompleteHandler() {
public AutoCompleteHandler getAutoCompleteHandler() {
return autoCompleteHandler;
}
@ -228,7 +228,8 @@ public class Command implements JDAEntity<CommandData> {
case CHAT_INPUT:
SlashCommandData slashCommandData = Commands.slash(getName(), Objects.requireNonNull(getDescription()));
slashCommandData.addSubcommandGroups(subCommandGroups.stream().map(JDAEntity::asJDA).toArray(SubcommandGroupData[]::new));
slashCommandData.addSubcommands(subCommands.stream().map(Command::asJDASubcommand).toArray(SubcommandData[]::new));
slashCommandData.addSubcommands(subCommands.stream().map(
DiscordCommand::asJDASubcommand).toArray(SubcommandData[]::new));
slashCommandData.addOptions(options.stream().map(JDAEntity::asJDA).toArray(OptionData[]::new));
commandData = slashCommandData;
break;
@ -252,9 +253,9 @@ public class Command implements JDAEntity<CommandData> {
private final Map<Locale, String> descriptionTranslations = new LinkedHashMap<>();
private final List<SubCommandGroup> subCommandGroups = new ArrayList<>();
private final List<Command> subCommands = new ArrayList<>();
private final List<DiscordCommand> subCommands = new ArrayList<>();
private final List<CommandOption> options = new ArrayList<>();
private Consumer<DiscordCommandAutoCompleteInteractionEvent> autoCompleteHandler;
private AutoCompleteHandler autoCompleteHandler;
private ChatInputBuilder(ComponentIdentifier id, String name, String description) {
super(id, CommandType.CHAT_INPUT, name);
@ -296,7 +297,7 @@ public class Command implements JDAEntity<CommandData> {
* @return this builder, useful for chaining
*/
@NotNull
public ChatInputBuilder addSubCommand(@NotNull Command command) {
public ChatInputBuilder addSubCommand(@NotNull DiscordCommand command) {
this.subCommands.add(command);
return this;
}
@ -319,14 +320,14 @@ public class Command implements JDAEntity<CommandData> {
* @return this builder, useful for chaining
*/
@NotNull
public ChatInputBuilder setAutoCompleteHandler(Consumer<DiscordCommandAutoCompleteInteractionEvent> autoCompleteHandler) {
public ChatInputBuilder setAutoCompleteHandler(AutoCompleteHandler autoCompleteHandler) {
this.autoCompleteHandler = autoCompleteHandler;
return this;
}
@Override
public Command build() {
return new Command(
public DiscordCommand build() {
return new DiscordCommand(
id,
type,
nameTranslations,
@ -343,6 +344,13 @@ public class Command implements JDAEntity<CommandData> {
}
}
@FunctionalInterface
public interface AutoCompleteHandler {
void autoComplete(DiscordCommandAutoCompleteInteractionEvent event);
}
public static class Builder<E extends AbstractCommandInteractionEvent<?>> {
protected final ComponentIdentifier id;
@ -414,8 +422,8 @@ public class Command implements JDAEntity<CommandData> {
return this;
}
public Command build() {
return new Command(
public DiscordCommand build() {
return new DiscordCommand(
id,
type,
nameTranslations,

View File

@ -43,15 +43,15 @@ public class SubCommandGroup implements JDAEntity<SubcommandGroupData> {
* @return a new sub command group
*/
@NotNull
public static SubCommandGroup of(@NotNull String name, @NotNull String description, @NotNull Command... commands) {
public static SubCommandGroup of(@NotNull String name, @NotNull String description, @NotNull DiscordCommand... commands) {
return new SubCommandGroup(name, description, Arrays.asList(commands));
}
private final String name;
private final String description;
private final List<Command> commands;
private final List<DiscordCommand> commands;
private SubCommandGroup(String name, String description, List<Command> commands) {
private SubCommandGroup(String name, String description, List<DiscordCommand> commands) {
this.name = name;
this.description = description;
this.commands = commands;
@ -69,13 +69,13 @@ public class SubCommandGroup implements JDAEntity<SubcommandGroupData> {
@NotNull
@Unmodifiable
public List<Command> getCommands() {
public List<DiscordCommand> getCommands() {
return commands;
}
@Override
public SubcommandGroupData asJDA() {
return new SubcommandGroupData(name, description)
.addSubcommands(commands.stream().map(Command::asJDASubcommand).toArray(SubcommandData[]::new));
.addSubcommands(commands.stream().map(DiscordCommand::asJDASubcommand).toArray(SubcommandData[]::new));
}
}

View File

@ -23,7 +23,7 @@
package com.discordsrv.api.discord.events.interaction.command;
import com.discordsrv.api.discord.entity.interaction.command.Command;
import com.discordsrv.api.discord.entity.interaction.command.DiscordCommand;
import com.discordsrv.api.event.events.Event;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;
@ -34,24 +34,24 @@ import java.util.Collections;
import java.util.List;
/**
* An event for registering {@link com.discordsrv.api.discord.entity.interaction.command.Command}s,
* an alternative to {@link com.discordsrv.api.discord.DiscordAPI#registerCommand(Command)}.
* An event for registering {@link DiscordCommand}s,
* an alternative to {@link com.discordsrv.api.discord.DiscordAPI#registerCommand(DiscordCommand)}.
*/
public class CommandRegisterEvent implements Event {
private final List<Command> commands = new ArrayList<>();
private final List<DiscordCommand> commands = new ArrayList<>();
/**
* Add events to be registered.
* @param commands the commands to be registered, use of the same command instances is recommended
*/
public void registerCommands(@NotNull Command... commands) {
public void registerCommands(@NotNull DiscordCommand... commands) {
this.commands.addAll(Arrays.asList(commands));
}
@NotNull
@Unmodifiable
public List<Command> getCommands() {
public List<DiscordCommand> getCommands() {
return Collections.unmodifiableList(commands);
}
}

View File

@ -47,16 +47,16 @@ public class DiscordCommandAutoCompleteInteractionEvent extends AbstractInteract
super(jdaEvent, identifier, user, member, channel);
}
public void addChoice(String key, String value) {
this.choices.put(key, value);
public void addChoice(String name, String value) {
this.choices.put(name, value);
}
public void addChoice(String key, double value) {
this.choices.put(key, value);
public void addChoice(String name, double value) {
this.choices.put(name, value);
}
public void addChoice(String key, long value) {
this.choices.put(key, value);
public void addChoice(String name, long value) {
this.choices.put(name, value);
}
public Map<String, Object> getChoices() {

View File

@ -0,0 +1,12 @@
package com.discordsrv.bukkit;
import org.bukkit.Server;
import java.util.Set;
public class PaperCmdMap {
public static Set<String> getMap(Server server) {
return server.getCommandMap().getKnownCommands().keySet();
}
}

View File

@ -39,6 +39,7 @@ import com.discordsrv.bukkit.scheduler.BukkitScheduler;
import com.discordsrv.bukkit.scheduler.FoliaScheduler;
import com.discordsrv.bukkit.scheduler.IBukkitScheduler;
import com.discordsrv.common.ServerDiscordSRV;
import com.discordsrv.common.command.discord.commands.subcommand.ExecuteCommand;
import com.discordsrv.common.command.game.handler.ICommandHandler;
import com.discordsrv.common.config.manager.ConnectionConfigManager;
import com.discordsrv.common.config.manager.MainConfigManager;
@ -47,11 +48,14 @@ import com.discordsrv.common.messageforwarding.game.minecrafttodiscord.Minecraft
import com.discordsrv.common.plugin.PluginManager;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import org.bukkit.Server;
import org.bukkit.command.Command;
import org.bukkit.plugin.ServicePriority;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
@ -225,4 +229,40 @@ public class BukkitDiscordSRV extends ServerDiscordSRV<DiscordSRVBukkitBootstrap
requiredLinkingListener.disable();
audiences.close();
}
public ExecuteCommand.AutoCompleteHelper autoCompleteHelper() {
return parts -> {
String commandName = !parts.isEmpty() ? parts.remove(0) : null;
Command command = commandName != null ? server().getPluginCommand(commandName) : null;
if (command == null) {
if (parts.size() > 1) {
// Command is not known but there are arguments, nothing to auto complete...
return Collections.emptyList();
} else {
// List out commands
List<String> suggestions = new ArrayList<>();
for (String cmd : PaperCmdMap.getMap(server())) {
if (commandName == null || cmd.startsWith(commandName)) {
suggestions.add(cmd);
}
}
return suggestions;
}
}
// Get the arguments minus the last one (if any)
String prefix = String.join(" ", parts.subList(0, parts.size() - (!parts.isEmpty() ? 1 : 0)));
if (!prefix.isEmpty()) {
prefix = prefix + " ";
}
List<String> suggestions = new ArrayList<>();
for (String suggestion : command.tabComplete(server().getConsoleSender(), commandName, parts.toArray(new String[0]))) {
suggestions.add(commandName + " " + prefix + suggestion);
}
return suggestions;
};
}
}

View File

@ -23,6 +23,7 @@ import com.discordsrv.api.module.type.Module;
import com.discordsrv.api.placeholder.DiscordPlaceholders;
import com.discordsrv.common.bootstrap.IBootstrap;
import com.discordsrv.common.channel.ChannelConfigHelper;
import com.discordsrv.common.command.discord.commands.subcommand.ExecuteCommand;
import com.discordsrv.common.command.game.handler.ICommandHandler;
import com.discordsrv.common.component.ComponentFactory;
import com.discordsrv.common.config.connection.ConnectionConfig;
@ -34,8 +35,8 @@ import com.discordsrv.common.debug.data.OnlineMode;
import com.discordsrv.common.debug.data.VersionInfo;
import com.discordsrv.common.dependency.DiscordSRVDependencyManager;
import com.discordsrv.common.discord.api.DiscordAPIImpl;
import com.discordsrv.common.discord.connection.jda.JDAConnectionManager;
import com.discordsrv.common.discord.connection.details.DiscordConnectionDetailsImpl;
import com.discordsrv.common.discord.connection.jda.JDAConnectionManager;
import com.discordsrv.common.linking.LinkProvider;
import com.discordsrv.common.logging.Logger;
import com.discordsrv.common.logging.impl.DiscordSRVLogger;
@ -152,4 +153,8 @@ public interface DiscordSRV extends DiscordSRVApi {
CompletableFuture<Void> invokeDisable();
CompletableFuture<List<ReloadResult>> invokeReload(Set<ReloadFlag> flags, boolean silent);
default ExecuteCommand.AutoCompleteHelper autoCompleteHelper() {
return null;
}
}

View File

@ -18,7 +18,7 @@
package com.discordsrv.common.command.combined.commands;
import com.discordsrv.api.discord.entity.interaction.command.Command;
import com.discordsrv.api.discord.entity.interaction.command.DiscordCommand;
import com.discordsrv.api.discord.entity.interaction.command.CommandOption;
import com.discordsrv.api.discord.entity.interaction.component.ComponentIdentifier;
import com.discordsrv.common.DiscordSRV;
@ -43,7 +43,7 @@ public class DebugCommand extends CombinedCommand {
private static DebugCommand INSTANCE;
private static GameCommand GAME;
private static Command DISCORD;
private static DiscordCommand DISCORD;
private static DebugCommand getInstance(DiscordSRV discordSRV) {
return INSTANCE != null ? INSTANCE : (INSTANCE = new DebugCommand(discordSRV));
@ -67,10 +67,10 @@ public class DebugCommand extends CombinedCommand {
return GAME;
}
public static Command getDiscord(DiscordSRV discordSRV) {
public static DiscordCommand getDiscord(DiscordSRV discordSRV) {
if (DISCORD == null) {
DebugCommand command = getInstance(discordSRV);
DISCORD = Command.chatInput(ComponentIdentifier.of("DiscordSRV", "debug"), "debug", "Create a debug report")
DISCORD = DiscordCommand.chatInput(ComponentIdentifier.of("DiscordSRV", "debug"), "debug", "Create a debug report")
.addOption(
CommandOption.builder(CommandOption.Type.STRING, "format", "The format to generate the debug report")
.addChoice(".zip", "zip")

View File

@ -1,6 +1,6 @@
package com.discordsrv.common.command.combined.commands;
import com.discordsrv.api.discord.entity.interaction.command.Command;
import com.discordsrv.api.discord.entity.interaction.command.DiscordCommand;
import com.discordsrv.api.discord.entity.interaction.component.ComponentIdentifier;
import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.command.combined.abstraction.CombinedCommand;
@ -24,7 +24,7 @@ public class ResyncCommand extends CombinedCommand {
private static ResyncCommand INSTANCE;
private static GameCommand GAME;
private static Command DISCORD;
private static DiscordCommand DISCORD;
private static ResyncCommand getInstance(DiscordSRV discordSRV) {
return INSTANCE != null ? INSTANCE : (INSTANCE = new ResyncCommand(discordSRV));
@ -41,10 +41,10 @@ public class ResyncCommand extends CombinedCommand {
return GAME;
}
public static Command getDiscord(DiscordSRV discordSRV) {
public static DiscordCommand getDiscord(DiscordSRV discordSRV) {
if (DISCORD == null) {
ResyncCommand command = getInstance(discordSRV);
DISCORD = Command.chatInput(ComponentIdentifier.of("DiscordSRV", "resync"), "resync", "Perform group resync for online players")
DISCORD = DiscordCommand.chatInput(ComponentIdentifier.of("DiscordSRV", "resync"), "resync", "Perform group resync for online players")
.setEventHandler(command)
.build();
}

View File

@ -19,7 +19,7 @@
package com.discordsrv.common.command.combined.commands;
import com.discordsrv.api.color.Color;
import com.discordsrv.api.discord.entity.interaction.command.Command;
import com.discordsrv.api.discord.entity.interaction.command.DiscordCommand;
import com.discordsrv.api.discord.entity.interaction.component.ComponentIdentifier;
import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.command.combined.abstraction.CombinedCommand;
@ -38,7 +38,7 @@ public class VersionCommand extends CombinedCommand {
private static VersionCommand INSTANCE;
private static GameCommand GAME;
private static Command DISCORD;
private static DiscordCommand DISCORD;
private static VersionCommand getInstance(DiscordSRV discordSRV) {
return INSTANCE != null ? INSTANCE : (INSTANCE = new VersionCommand(discordSRV));
@ -55,10 +55,10 @@ public class VersionCommand extends CombinedCommand {
return GAME;
}
public static Command getDiscord(DiscordSRV discordSRV) {
public static DiscordCommand getDiscord(DiscordSRV discordSRV) {
if (DISCORD == null) {
VersionCommand command = getInstance(discordSRV);
DISCORD = Command.chatInput(ComponentIdentifier.of("DiscordSRV", "version"), "version", "Get the DiscordSRV version")
DISCORD = DiscordCommand.chatInput(ComponentIdentifier.of("DiscordSRV", "version"), "version", "Get the DiscordSRV version")
.setEventHandler(command)
.build();
}

View File

@ -1,26 +1,28 @@
package com.discordsrv.common.command.discord.commands;
import com.discordsrv.api.discord.entity.interaction.command.Command;
import com.discordsrv.api.discord.entity.interaction.command.DiscordCommand;
import com.discordsrv.api.discord.entity.interaction.component.ComponentIdentifier;
import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.command.combined.commands.DebugCommand;
import com.discordsrv.common.command.combined.commands.ResyncCommand;
import com.discordsrv.common.command.combined.commands.VersionCommand;
import com.discordsrv.common.command.discord.commands.subcommand.ExecuteCommand;
public class DiscordSRVDiscordCommand {
private static final ComponentIdentifier IDENTIFIER = ComponentIdentifier.of("DiscordSRV", "discordsrv");
private static Command INSTANCE;
private static DiscordCommand INSTANCE;
public static Command get(DiscordSRV discordSRV) {
public static DiscordCommand get(DiscordSRV discordSRV) {
if (INSTANCE == null) {
INSTANCE = Command.chatInput(IDENTIFIER, "discordsrv", "DiscordSRV related commands")
INSTANCE = DiscordCommand.chatInput(IDENTIFIER, "discordsrv", "DiscordSRV related commands")
.addSubCommand(DebugCommand.getDiscord(discordSRV))
.addSubCommand(VersionCommand.getDiscord(discordSRV))
.addSubCommand(ResyncCommand.getDiscord(discordSRV))
.addSubCommand(ExecuteCommand.get(discordSRV))
.setGuildOnly(false)
.setDefaultPermission(Command.DefaultPermission.ADMINISTRATOR)
.setDefaultPermission(DiscordCommand.DefaultPermission.ADMINISTRATOR)
.build();
}

View File

@ -0,0 +1,88 @@
package com.discordsrv.common.command.discord.commands.subcommand;
import com.discordsrv.api.discord.entity.interaction.command.CommandOption;
import com.discordsrv.api.discord.entity.interaction.command.DiscordCommand;
import com.discordsrv.api.discord.entity.interaction.component.ComponentIdentifier;
import com.discordsrv.api.discord.events.interaction.command.DiscordChatInputInteractionEvent;
import com.discordsrv.api.discord.events.interaction.command.DiscordCommandAutoCompleteInteractionEvent;
import com.discordsrv.common.DiscordSRV;
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
public class ExecuteCommand implements Consumer<DiscordChatInputInteractionEvent>, DiscordCommand.AutoCompleteHandler {
private static DiscordCommand INSTANCE;
public static DiscordCommand get(DiscordSRV discordSRV) {
if (INSTANCE == null) {
ExecuteCommand command = new ExecuteCommand(discordSRV);
INSTANCE = DiscordCommand.chatInput(ComponentIdentifier.of("DiscordSRV", "execute"), "execute", "Run a Minecraft console command")
.addOption(
CommandOption.builder(CommandOption.Type.STRING, "command", "The command to execute")
.setAutoComplete(true)
.setRequired(true)
.build()
)
.setAutoCompleteHandler(command)
.setEventHandler(command)
.build();
}
return INSTANCE;
}
private final DiscordSRV discordSRV;
public ExecuteCommand(DiscordSRV discordSRV) {
this.discordSRV = discordSRV;
}
@Override
public void accept(DiscordChatInputInteractionEvent event) {
OptionMapping mapping = event.asJDA().getOption("command");
if (mapping == null) {
return;
}
String command = mapping.getAsString();
discordSRV.logger().error("> " + command);
}
@Override
public void autoComplete(DiscordCommandAutoCompleteInteractionEvent event) {
OptionMapping mapping = event.asJDA().getOption("command");
if (mapping == null) {
return;
}
String command = mapping.getAsString();
List<String> parts = new ArrayList<>(Arrays.asList(command.split(" ")));
AutoCompleteHelper helper = discordSRV.autoCompleteHelper();
List<String> suggestions = helper.suggestCommands(new ArrayList<>(parts));
if (suggestions.isEmpty() || suggestions.contains(command)) {
parts.add("");
suggestions = new ArrayList<>(helper.suggestCommands(parts));
if (suggestions.isEmpty()) {
suggestions.add(command);
}
}
for (String suggestion : suggestions) {
if (event.getChoices().size() >= 25) break;
event.addChoice(suggestion, suggestion);
}
}
public interface AutoCompleteHelper {
List<String> suggestCommands(List<String> parts);
}
}

View File

@ -23,6 +23,7 @@ import com.discordsrv.api.discord.entity.channel.DiscordMessageChannel;
import com.discordsrv.api.discord.entity.guild.DiscordGuildMember;
import com.discordsrv.api.discord.entity.interaction.DiscordInteractionHook;
import com.discordsrv.api.discord.entity.interaction.command.CommandType;
import com.discordsrv.api.discord.entity.interaction.command.DiscordCommand;
import com.discordsrv.api.discord.entity.interaction.command.SubCommandGroup;
import com.discordsrv.api.discord.entity.interaction.component.ComponentIdentifier;
import com.discordsrv.api.discord.events.interaction.DiscordModalInteractionEvent;
@ -130,7 +131,7 @@ public class DiscordAPIEventModule extends AbstractModule<DiscordSRV> {
DiscordGuildMember guildMember = member != null ? api().getGuildMember(member) : null;
DiscordMessageChannel channel = api().getMessageChannel(event.getMessageChannel());
if (event instanceof CommandAutoCompleteInteractionEvent) {
com.discordsrv.api.discord.entity.interaction.command.Command command = discordSRV.discordAPI().getActiveCommand(
DiscordCommand command = discordSRV.discordAPI().getActiveCommand(
((CommandAutoCompleteInteractionEvent) event).isGuildCommand() ? event.getGuild() : null,
CommandType.CHAT_INPUT,
((CommandAutoCompleteInteractionEvent) event).getName()
@ -138,25 +139,30 @@ public class DiscordAPIEventModule extends AbstractModule<DiscordSRV> {
if (command == null) {
return;
}
command = mapCommand(
command,
((CommandAutoCompleteInteractionEvent) event).getSubcommandGroup(),
((CommandAutoCompleteInteractionEvent) event).getSubcommandName()
);
DiscordCommandAutoCompleteInteractionEvent autoComplete = new DiscordCommandAutoCompleteInteractionEvent(
(CommandAutoCompleteInteractionEvent) event, command.getId(), user, guildMember, channel);
discordSRV.eventBus().publish(autoComplete);
Consumer<DiscordCommandAutoCompleteInteractionEvent> autoCompleteHandler = command.getAutoCompleteHandler();
DiscordCommand.AutoCompleteHandler autoCompleteHandler = command.getAutoCompleteHandler();
if (autoCompleteHandler != null) {
autoCompleteHandler.accept(autoComplete);
autoCompleteHandler.autoComplete(autoComplete);
}
List<Command.Choice> choices = new ArrayList<>();
for (Map.Entry<String, Object> entry : autoComplete.getChoices().entrySet()) {
String key = entry.getKey();
String name = entry.getKey();
Object value = entry.getValue();
if (value instanceof String) {
choices.add(new Command.Choice(key, (String) value));
choices.add(new Command.Choice(name, (String) value));
} else if (value instanceof Double || value instanceof Float) {
choices.add(new Command.Choice(key, ((Number) value).doubleValue()));
choices.add(new Command.Choice(name, ((Number) value).doubleValue()));
} else {
choices.add(new Command.Choice(key, ((Number) value).longValue()));
choices.add(new Command.Choice(name, ((Number) value).longValue()));
}
}
((CommandAutoCompleteInteractionEvent) event).replyChoices(choices).queue();
@ -169,7 +175,7 @@ public class DiscordAPIEventModule extends AbstractModule<DiscordSRV> {
Guild guild = ((GenericCommandInteractionEvent) event).isGuildCommand() ? event.getGuild() : null;
String name = ((GenericCommandInteractionEvent) event).getName();
if (event instanceof MessageContextInteractionEvent) {
com.discordsrv.api.discord.entity.interaction.command.Command command = discordSRV.discordAPI()
DiscordCommand command = discordSRV.discordAPI()
.getActiveCommand(guild, CommandType.MESSAGE, name).orElse(null);
if (command == null) {
return;
@ -190,7 +196,7 @@ public class DiscordAPIEventModule extends AbstractModule<DiscordSRV> {
eventHandler.accept(interactionEvent);
}
} else if (event instanceof UserContextInteractionEvent) {
com.discordsrv.api.discord.entity.interaction.command.Command command = discordSRV.discordAPI()
DiscordCommand command = discordSRV.discordAPI()
.getActiveCommand(guild, CommandType.USER, name).orElse(null);
if (command == null) {
return;
@ -211,35 +217,16 @@ public class DiscordAPIEventModule extends AbstractModule<DiscordSRV> {
eventHandler.accept(interactionEvent);
}
} else if (event instanceof SlashCommandInteractionEvent) {
com.discordsrv.api.discord.entity.interaction.command.Command command = discordSRV.discordAPI()
DiscordCommand command = discordSRV.discordAPI()
.getActiveCommand(guild, CommandType.CHAT_INPUT, name).orElse(null);
if (command == null) {
return;
}
String subCommandGroupName = ((SlashCommandInteractionEvent) event).getSubcommandGroup();
String subCommandName = ((SlashCommandInteractionEvent) event).getSubcommandName();
if (subCommandGroupName != null) {
for (SubCommandGroup group : command.getSubCommandGroups()) {
if (group.getName().equals(subCommandGroupName)) {
for (com.discordsrv.api.discord.entity.interaction.command.Command subCommand : group.getCommands()) {
if (subCommand.getName().equals(subCommandName)) {
command = subCommand;
break;
}
}
break;
}
}
} else if (subCommandName != null) {
for (com.discordsrv.api.discord.entity.interaction.command.Command subCommand : command.getSubCommands()) {
if (subCommandName.equals(subCommand.getName())) {
command = subCommand;
break;
}
}
}
command = mapCommand(
command,
((SlashCommandInteractionEvent) event).getSubcommandGroup(),
((SlashCommandInteractionEvent) event).getSubcommandName()
);
DiscordChatInputInteractionEvent interactionEvent = new DiscordChatInputInteractionEvent(
(SlashCommandInteractionEvent) event,
@ -283,4 +270,28 @@ public class DiscordAPIEventModule extends AbstractModule<DiscordSRV> {
discordSRV.eventBus().publish(newEvent);
}
}
private DiscordCommand mapCommand(DiscordCommand command, String subCommandGroupName, String subCommandName) {
if (subCommandGroupName != null) {
for (SubCommandGroup group : command.getSubCommandGroups()) {
if (group.getName().equals(subCommandGroupName)) {
for (DiscordCommand subCommand : group.getCommands()) {
if (subCommand.getName().equals(subCommandName)) {
command = subCommand;
break;
}
}
break;
}
}
} else if (subCommandName != null) {
for (DiscordCommand subCommand : command.getSubCommands()) {
if (subCommandName.equals(subCommand.getName())) {
command = subCommand;
break;
}
}
}
return command;
}
}

View File

@ -27,8 +27,8 @@ import com.discordsrv.api.discord.entity.DiscordUser;
import com.discordsrv.api.discord.entity.channel.*;
import com.discordsrv.api.discord.entity.guild.DiscordGuild;
import com.discordsrv.api.discord.entity.guild.DiscordRole;
import com.discordsrv.api.discord.entity.interaction.command.Command;
import com.discordsrv.api.discord.entity.interaction.command.CommandType;
import com.discordsrv.api.discord.entity.interaction.command.DiscordCommand;
import com.discordsrv.api.discord.exception.NotReadyException;
import com.discordsrv.api.discord.exception.RestErrorResponseException;
import com.discordsrv.common.DiscordSRV;
@ -472,16 +472,16 @@ public class DiscordAPIImpl implements DiscordAPI {
}
@Override
public Command.RegistrationResult registerCommand(Command command) {
public DiscordCommand.RegistrationResult registerCommand(DiscordCommand command) {
return commandRegistry.register(command, false);
}
@Override
public void unregisterCommand(Command command) {
public void unregisterCommand(DiscordCommand command) {
commandRegistry.unregister(command);
}
public Optional<Command> getActiveCommand(@Nullable Guild guild, CommandType type, String name) {
public Optional<DiscordCommand> getActiveCommand(@Nullable Guild guild, CommandType type, String name) {
return Optional.ofNullable(commandRegistry.getActive(guild != null ? guild.getIdLong() : null, type, name));
}

View File

@ -19,7 +19,7 @@
package com.discordsrv.common.discord.api;
import com.discordsrv.api.discord.entity.JDAEntity;
import com.discordsrv.api.discord.entity.interaction.command.Command;
import com.discordsrv.api.discord.entity.interaction.command.DiscordCommand;
import com.discordsrv.api.discord.entity.interaction.command.CommandType;
import com.discordsrv.api.discord.events.interaction.command.CommandRegisterEvent;
import com.discordsrv.common.DiscordSRV;
@ -50,7 +50,7 @@ public class DiscordCommandRegistry {
CommandRegisterEvent event = new CommandRegisterEvent();
discordSRV.eventBus().publish(event);
List<Command> commands = event.getCommands();
List<DiscordCommand> commands = event.getCommands();
for (Map<CommandType, Registry> registryMap : registries.values()) {
registryMap.values().forEach(registry -> registry.removeIf(reg -> reg.isTemporary() && !commands.contains(reg.getCommand())));
}
@ -58,27 +58,27 @@ public class DiscordCommandRegistry {
commands.forEach(cmd -> register(cmd, true));
}
public Command.RegistrationResult register(Command command, boolean temporary) {
public DiscordCommand.RegistrationResult register(DiscordCommand command, boolean temporary) {
CommandType type = command.getType();
Long guildId = command.getGuildId();
Registry registry = registries
.computeIfAbsent(guildId != null ? guildId : GLOBAL_ID, key -> new EnumMap<>(CommandType.class))
.computeIfAbsent(type, key -> new Registry());
if (registry.contains(command)) {
return Command.RegistrationResult.ALREADY_REGISTERED;
return DiscordCommand.RegistrationResult.ALREADY_REGISTERED;
}
boolean first = registry.register(command, temporary);
if (!first) {
return Command.RegistrationResult.NAME_ALREADY_IN_USE;
return DiscordCommand.RegistrationResult.NAME_ALREADY_IN_USE;
}
if (registry.getInTimeOrder().indexOf(command) >= type.getMaximumCount()) {
return Command.RegistrationResult.TOO_MANY_COMMANDS;
return DiscordCommand.RegistrationResult.TOO_MANY_COMMANDS;
}
return Command.RegistrationResult.REGISTERED;
return DiscordCommand.RegistrationResult.REGISTERED;
}
public void unregister(Command command) {
public void unregister(DiscordCommand command) {
Long guildId = command.getGuildId();
Registry registry = registries
.computeIfAbsent(guildId != null ? guildId : GLOBAL_ID, key -> Collections.emptyMap())
@ -90,7 +90,7 @@ public class DiscordCommandRegistry {
}
@Nullable
public Command getActive(Long guildId, CommandType type, String name) {
public DiscordCommand getActive(Long guildId, CommandType type, String name) {
Registry registry = registries
.computeIfAbsent(guildId != null ? guildId : GLOBAL_ID, key -> Collections.emptyMap())
.get(type);
@ -114,23 +114,23 @@ public class DiscordCommandRegistry {
for (long guildId : ids) {
Map<CommandType, Registry> commandsByType = registries.getOrDefault(guildId, Collections.emptyMap());
Map<CommandType, Set<Command>> commandsToRegister = new EnumMap<>(CommandType.class);
Map<CommandType, Set<DiscordCommand>> commandsToRegister = new EnumMap<>(CommandType.class);
boolean updateNeeded = false;
for (Map.Entry<CommandType, Registry> entry : commandsByType.entrySet()) {
Registry registry = entry.getValue();
List<Command> commands = registry.getInTimeOrder();
Set<Command> currentCommands = new LinkedHashSet<>();
List<DiscordCommand> commands = registry.getInTimeOrder();
Set<DiscordCommand> currentCommands = new LinkedHashSet<>();
int max = Math.min(commands.size(), entry.getKey().getMaximumCount());
for (int i = 0; i < max; i++) {
Command command = commands.get(i);
DiscordCommand command = commands.get(i);
currentCommands.add(command);
}
commandsToRegister.put(entry.getKey(), currentCommands);
Collection<Command> activeCommands = registry.activeCommands.values();
Collection<DiscordCommand> activeCommands = registry.activeCommands.values();
if (activeCommands.size() != currentCommands.size() || !currentCommands.containsAll(activeCommands)) {
updateNeeded = true;
}
@ -148,7 +148,7 @@ public class DiscordCommandRegistry {
action = guild.updateCommands();
}
List<Command> allCommands = new ArrayList<>();
List<DiscordCommand> allCommands = new ArrayList<>();
commandsToRegister.values().forEach(allCommands::addAll);
action.addCommands(allCommands.stream().map(JDAEntity::asJDA).collect(Collectors.toList()))
.queue(v -> {
@ -166,7 +166,7 @@ public class DiscordCommandRegistry {
private static class Registry {
private final Map<String, List<Registration>> registry = new ConcurrentHashMap<>();
private final Map<String, Command> activeCommands = new HashMap<>();
private final Map<String, DiscordCommand> activeCommands = new HashMap<>();
public void removeIf(Predicate<Registration> commandPredicate) {
List<String> removeKeys = new ArrayList<>();
@ -180,7 +180,7 @@ public class DiscordCommandRegistry {
removeKeys.forEach(registry::remove);
}
public boolean contains(@NotNull Command command) {
public boolean contains(@NotNull DiscordCommand command) {
List<Registration> commands = registry.get(command.getName());
if (commands == null) {
return false;
@ -189,14 +189,14 @@ public class DiscordCommandRegistry {
return commands.stream().anyMatch(reg -> reg.getCommand() == command);
}
public boolean register(@NotNull Command command, boolean temporary) {
public boolean register(@NotNull DiscordCommand command, boolean temporary) {
List<Registration> commands = registry.computeIfAbsent(command.getName(), key -> new CopyOnWriteArrayList<>());
boolean empty = commands.isEmpty();
commands.add(new Registration(command, temporary));
return empty;
}
public void unregister(@NotNull Command command) {
public void unregister(@NotNull DiscordCommand command) {
List<Registration> commands = registry.get(command.getName());
if (commands == null) {
return;
@ -208,16 +208,16 @@ public class DiscordCommandRegistry {
}
}
public void putActiveCommands(Set<Command> commands) {
public void putActiveCommands(Set<DiscordCommand> commands) {
synchronized (activeCommands) {
activeCommands.clear();
for (Command command : commands) {
for (DiscordCommand command : commands) {
activeCommands.put(command.getName(), command);
}
}
}
public List<Command> getInTimeOrder() {
public List<DiscordCommand> getInTimeOrder() {
List<Registration> registrations = registry.values().stream()
.map(list -> list.get(0))
.collect(Collectors.toList());
@ -229,7 +229,7 @@ public class DiscordCommandRegistry {
}
@Nullable
public Command getActive(String name) {
public DiscordCommand getActive(String name) {
synchronized (activeCommands) {
return activeCommands.get(name);
}
@ -238,17 +238,17 @@ public class DiscordCommandRegistry {
private static class Registration {
private final Command command;
private final DiscordCommand command;
private final long time;
private final boolean temporary;
public Registration(Command command, boolean temporary) {
public Registration(DiscordCommand command, boolean temporary) {
this.command = command;
this.time = System.currentTimeMillis();
this.temporary = temporary;
}
public Command getCommand() {
public DiscordCommand getCommand() {
return command;
}