channels, int memberCount, String name, String id) {
static GuildStructure fromGuild(Guild guild) {
return new GuildStructure(guild.getChannels().stream().map(ChannelStructure::fromChannel).toList(), guild.getMemberCount(), guild.getName(), guild.getId());
}
}
+ /**
+ * Represents a structure for a channel within a guild, encapsulating its unique identifier, the guild it belongs to, and its name.
+ * @param id The unique identifier of the channel. This serves as a primary key for identifying the channel within the Discord API, allowing for precise operations related to this specific channel.
+ * @param guild The unique identifier of the guild to which this channel belongs. This provides context about the guild structure and allows for operations that are specific to the guild.
+ * @param name The name of the channel. This is a human-readable identifier for the channel, making it easier to recognize and refer to. It can be used in user interfaces or logs to display the channel's name instead of its ID.
+ */
public record ChannelStructure(String id, String guild, String name) {
static ChannelStructure fromChannel(GuildChannel channel) {
return new ChannelStructure(channel.getId(), channel.getGuild().getId(), channel.getName());
}
}
+ /**
+ * Represents a structure for a member within a guild, encapsulating their unique identifier, the guild they belong to, and their name.
+ * @param id The unique identifier of the member. This serves as a primary key for identifying the member within the Discord API, allowing for precise operations related to this specific member.
+ * @param guild The {@link GuildStructure} representing the guild to which this member belongs. This provides context about the guild structure and allows for operations that are specific to the guild.
+ * @param name The name of the member as it would be displayed in Discord. This is a human-readable identifier for the member, making it easier to recognize and refer to them. It can be used in user interfaces or logs to display the member's name instead of their ID.
+ */
public record MemberStructure(String id, GuildStructure guild, String name) {
static MemberStructure fromMember(Member member) {
return new MemberStructure(member.getId(), GuildStructure.fromGuild(member.getGuild()), member.getEffectiveName());
diff --git a/src/main/java/botcommons/commands/AutoCompleteHandler.java b/src/main/java/botcommons/commands/AutoCompleteHandler.java
index 7b88119..a3c50b2 100644
--- a/src/main/java/botcommons/commands/AutoCompleteHandler.java
+++ b/src/main/java/botcommons/commands/AutoCompleteHandler.java
@@ -5,5 +5,9 @@
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoCompleteHandler {
+ /**
+ * The name of the command that this auto complete handler is for.
+ * @return value
+ */
String[] value();
}
diff --git a/src/main/java/botcommons/commands/Command.java b/src/main/java/botcommons/commands/Command.java
index 541d0fb..b005acd 100644
--- a/src/main/java/botcommons/commands/Command.java
+++ b/src/main/java/botcommons/commands/Command.java
@@ -8,6 +8,13 @@
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+/**
+ * This annotation is used to define a command for the bot.
+ *
+ * The name, help, aliases, usage, category and permission can be specified.
+ *
+ * The userContext defines where this command can be used (e.g. GUILD, PRIVATE_CHANNEL)
+ */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Command {
diff --git a/src/main/java/botcommons/commands/CommandHolder.java b/src/main/java/botcommons/commands/CommandHolder.java
index 42fdf71..504140c 100644
--- a/src/main/java/botcommons/commands/CommandHolder.java
+++ b/src/main/java/botcommons/commands/CommandHolder.java
@@ -2,7 +2,9 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-
+/**
+ * This annotation is used to define a command holder class.
+ */
@Retention(RetentionPolicy.RUNTIME)
public @interface CommandHolder {
String group() default "N/A";
diff --git a/src/main/java/botcommons/commands/CommandInfo.java b/src/main/java/botcommons/commands/CommandInfo.java
index c63b369..040c21c 100644
--- a/src/main/java/botcommons/commands/CommandInfo.java
+++ b/src/main/java/botcommons/commands/CommandInfo.java
@@ -16,17 +16,27 @@
import java.util.List;
import java.util.function.Predicate;
+/**
+ * This class holds information about a command.
+ */
@SuppressWarnings("unused")
public class CommandInfo {
private static final HashMap, OptionType> optionTypeParams = new HashMap<>() {{
put(String.class, OptionType.STRING);
put(Integer.class, OptionType.INTEGER);
+ put(int.class, OptionType.INTEGER);
put(Boolean.class, OptionType.BOOLEAN);
+ put(boolean.class, OptionType.BOOLEAN);
put(Long.class, OptionType.INTEGER);
+ put(long.class, OptionType.INTEGER);
put(Double.class, OptionType.NUMBER);
+ put(double.class, OptionType.NUMBER);
put(Float.class, OptionType.NUMBER);
+ put(float.class, OptionType.NUMBER);
put(Short.class, OptionType.INTEGER);
+ put(short.class, OptionType.INTEGER);
put(Byte.class, OptionType.INTEGER);
+ put(byte.class, OptionType.INTEGER);
put(Character.class, OptionType.STRING);
put(List.class, OptionType.STRING);
put(ArrayList.class, OptionType.STRING);
@@ -51,10 +61,20 @@ public class CommandInfo {
public String usage = "";
public Method method;
+ /**
+ * Get the option with the specified name.
+ * @param name the name of the option to retrieve
+ * @return the {@link CommandInfo.Option} with the specified name, or null if no such option exists
+ */
public CommandInfo.Option getOption(String name) {
return Arrays.stream(args).filter(option -> option.name.equals(name)).findFirst().orElse(null);
}
+ /**
+ * Creates a CommandInfo instance from a method with the {@link Command} annotation.
+ * @param command the method to create the {@link CommandInfo} from. This method must have the {@link Command} annotation.
+ * @return a {@link CommandInfo} instance containing the information from the method.
+ */
public static CommandInfo from(@Nullable Method command) {
if (command == null)
return null;
@@ -96,6 +116,11 @@ public static CommandInfo from(@Nullable Method command) {
return info;
}
+ /**
+ * Creates a CommandInfo instance from a {@link GenericCommandEvent}.
+ * @param event the {@link GenericCommandEvent} to create the {@link CommandInfo} from. This event should be associated with a command.
+ * @return a {@link CommandInfo} instance containing the information from the event.
+ */
public static CommandInfo from(GenericCommandEvent event) {
boolean sub = event.getSubcommandName() != null || event.getSubcommandGroup() != null;
String command = sub ? event.getCommandName() + (event.getSubcommandGroup()!=null? " " + event.getSubcommandGroup() + " ": " ") +
@@ -104,6 +129,9 @@ public static CommandInfo from(GenericCommandEvent event) {
return from(CommandManager.getCommand(command));
}
+ /**
+ * Represents an option (argument) for a command.
+ */
@Getter
public static class Option {
private String name;
diff --git a/src/main/java/botcommons/commands/CommandManager.java b/src/main/java/botcommons/commands/CommandManager.java
index c949c51..20e3a5a 100644
--- a/src/main/java/botcommons/commands/CommandManager.java
+++ b/src/main/java/botcommons/commands/CommandManager.java
@@ -25,6 +25,11 @@
import java.util.*;
import java.util.function.Function;
+/**
+ * This class manages the commands for the bot.
+ *
+ * Call {@link #init(JDA)} to initialize the command manager.
+ */
public class CommandManager extends ListenerAdapter {
private static final HashMap commands = new HashMap<>();
private static final HashMap>> subcommands = new HashMap<>();
@@ -34,15 +39,28 @@ private CommandManager() {}
private static Function commandRunCheck = ($) -> true;
+ /**
+ * This method initializes the command manager with a JDA instance and a command run check function.
+ * @param jda The JDA instance to register the commands with.
+ * @param commandRunCheck A function that takes a {@link GenericCommandEvent} and returns a boolean indicating whether the command should be executed or not.
+ */
public static void init(JDA jda, Function commandRunCheck) {
init(jda);
CommandManager.commandRunCheck = commandRunCheck;
}
+ /**
+ * This method initializes the command manager with a JDA instance.
+ * @param jda The JDA instance to register the commands with.
+ */
public static void init(JDA jda) {
jda.addEventListener(new CommandManager());
}
+ /**
+ * This method adds command holders to the command manager.
+ * @param holders The classes that hold the commands. Each class should be annotated with {@link CommandHolder}.
+ */
public static void addCommands(Class>... holders) {
for (var holder : holders) {
CommandHolder meta = holder.getAnnotation(CommandHolder.class);
@@ -70,6 +88,10 @@ public static void addCommands(Class>... holders) {
}
}
+ /**
+ * This method adds subcommands to the command manager.
+ * @param holder The class that holds the subcommands. This class should be annotated with {@link CommandHolder}.
+ */
private static void addSubcommands(Class> holder) {
CommandHolder meta = holder.getAnnotation(CommandHolder.class);
if (meta == null) {
@@ -244,6 +266,11 @@ private static boolean checks(CommandInfo info, GenericCommandEvent event, Metho
put(OptionType.UNKNOWN, Object.class);
}};
+ /**
+ * This method retrieves the command method associated with a given command string.
+ * @param command The command string to look up. This can be the name of the command or an alias.
+ * @return The method associated with the command, or null if no matching command is found.
+ */
public static Method getCommand(String command) {
// First, check if the command is a direct match or an alias
Method possibleCommand = commands.entrySet().stream()
diff --git a/src/main/java/botcommons/commands/GenericCommandEvent.java b/src/main/java/botcommons/commands/GenericCommandEvent.java
index 672906d..6bd7081 100644
--- a/src/main/java/botcommons/commands/GenericCommandEvent.java
+++ b/src/main/java/botcommons/commands/GenericCommandEvent.java
@@ -24,7 +24,11 @@
import java.util.function.Function;
import java.util.function.Predicate;
-// Ignore possible null issues
+/**
+ * This class represents a generic command event for slash commands.
+ * It wraps the {@link SlashCommandInteractionEvent} and provides additional utility methods
+ * for handling command arguments and replies.
+ */
@SuppressWarnings({"ConstantConditions", "unused"})
public class GenericCommandEvent {
private final SlashCommandInteractionEvent slashCommandEvent;
@@ -35,70 +39,126 @@ private GenericCommandEvent(SlashCommandInteractionEvent slashCommandEvent) {
this.slashCommandEvent = slashCommandEvent;
}
+ /**
+ * Creates a new instance of {@link GenericCommandEvent} from a {@link SlashCommandInteractionEvent}.
+ * @param event The {@link SlashCommandInteractionEvent} to wrap.
+ * @return A new instance of {@link GenericCommandEvent} that wraps the provided {@link SlashCommandInteractionEvent}.
+ */
public static GenericCommandEvent of(@NotNull SlashCommandInteractionEvent event) {
GenericCommandEvent e = new GenericCommandEvent(event);
e.replyContext = new ReplyContext(event);
return e;
}
+ /**
+ * @return Returns the {@link JDA} instance associated with this command event.
+ */
public JDA getJDA() {
return slashCommandEvent.getJDA();
}
+ /**
+ * @return Returns true if the command was invoked from a guild (server), false otherwise.
+ */
public boolean isGuild() {
return slashCommandEvent.isFromGuild();
}
+ /**
+ * @return Returns true if the command was invoked in an area the bot can't access
+ */
public boolean isDetached() {
return slashCommandEvent.getChannel().isDetached();
}
+ /**
+ * @return Returns the {@link Guild} associated with this command event, or null if the command was invoked in a private channel (DM).
+ */
@Nullable
public Guild getGuild() {
return slashCommandEvent.getGuild();
}
+ /**
+ * @return Returns the ID of the guild associated with this command event.
+ * If the command was invoked in a private channel (DM), it returns "-1".
+ */
public String getGuildId() {
return isGuild()? getGuild().getId():"-1";
}
+ /**
+ * @return Returns the user who invoked the command.
+ */
public User getUser() {
return slashCommandEvent.getUser();
}
+ /**
+ * @return Returns the ID of the user who invoked the command.
+ */
public String getUserId() {
return getUser().getId();
}
+ /**
+ * @return Returns the member who invoked the command in a guild context, or null if the command was invoked in a private channel (DM).
+ */
@Nullable
public Member getMember() {
return slashCommandEvent.getMember();
}
+ /**
+ * @return The {@link SlashCommandInteraction} associated with this command event.
+ */
public SlashCommandInteraction getSlashCommandInteraction() {
return slashCommandEvent.getInteraction();
}
+ /**
+ * @return Returns the {@link MessageChannel} where the command was invoked.
+ */
public MessageChannel getChannel() {
return slashCommandEvent.getChannel();
}
+ /**
+ * @return Returns the name of the command that was invoked.
+ * This is the name of the slash command as defined when it was registered.
+ */
public String getCommandName() {
return slashCommandEvent.getName();
}
+ /**
+ * @return Returns the name of the subcommand that was invoked, if applicable.
+ */
public String getSubcommandName() {
return slashCommandEvent.getSubcommandName();
}
+ /**
+ * @return Returns the name of the subcommand group that was invoked, if applicable.
+ * This is useful for commands that have subcommand groups.
+ */
public String getSubcommandGroup() {
return slashCommandEvent.getSubcommandGroup();
}
+ /**
+ * @deprecated Useless, text commands are no longer supported.
+ * @return Returns true if this command is a slash command. (always)
+ */
+ @Deprecated(forRemoval = true)
boolean isSlashCommand() {
return true;
}
+ /**
+ * This method retrieves the arguments passed to the command in a structured way.
+ * @return An array of {@link Data} objects representing the options passed to the command.
+ */
public Data[] getArgs() {
return Arrays.stream(slashCommandEvent.getOptions().toArray(OptionMapping[]::new)).map(
optionMapping -> {
@@ -124,6 +184,13 @@ public record Data(CommandInfo.Option option, Object value) {
}
+ /**
+ * This method retrieves the value of a specific argument by its name and casts it to the specified type.
+ * @param name The name of the argument to retrieve. This should match the name of the option as defined in the command registration.
+ * @param type The class type to which the argument value should be cast. This allows for type-safe retrieval of the argument value.
+ * @return The value of the argument cast to the specified type, or null if the argument is not present or cannot be cast to the specified type.
+ * @param The type of the argument to retrieve. This is a generic type parameter that allows the method to return the value in the desired type.
+ */
public T getArg(String name, Class type) {
CommandInfo from = CommandInfo.from(this);
CommandInfo.Option option = from.getOption(name);
@@ -147,6 +214,9 @@ public T getArg(String name, Class type) {
return null;
}
+ /**
+ * @return Returns the {@link botcommons.config.ConfigManager.Config} associated with the current guild.
+ */
public ConfigManager.Config getConfig() {
return ConfigManager.getInstance().getConfigs().get(getGuildId());
}
@@ -194,6 +264,13 @@ public ReplyContext replyMenu(String menuId, Object... args) {
return this.replyContext.menu(menuId, args);
}
+ /**
+ * This method registers a menu with a specific ID and then returns the reply context for that menu.
+ * @param id The ID to register the menu with. This should be unique to avoid conflicts with other menus.
+ * @param menu The {@link BaseMenu} instance to register. This represents the menu that will be displayed to the user when they interact with the command.
+ * @param args Additional arguments to pass to the menu when it is invoked. This allows for dynamic content to be passed into the menu, such as user-specific data or command context.
+ * @return Returns the {@link ReplyContext} associated with the registered menu. This allows for further customization of the reply context, such as adding more options or handling user interactions with the menu.
+ */
public ReplyContext replyMenu(String id, BaseMenu menu, Object... args) {
MenuManager.registerMenuWithId(id+"-fake", menu);
System.out.println("Registered menu with id: " + id);
diff --git a/src/main/java/botcommons/commands/Param.java b/src/main/java/botcommons/commands/Param.java
index 2bf6f73..c4414fc 100644
--- a/src/main/java/botcommons/commands/Param.java
+++ b/src/main/java/botcommons/commands/Param.java
@@ -5,11 +5,34 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+/**
+ * This annotation is used to define a parameter for a command method.
+ */
@Retention(RetentionPolicy.RUNTIME)
public @interface Param {
+ /**
+ * The name of the parameter.
+ */
String description();
+
+ /**
+ * Whether this parameter is required or optional.
+ */
boolean required() default true;
+
+ /**
+ * An array of choices for the parameter. This is used to provide a list of valid options for the parameter in the command interface.
+ */
String[] choices() default {};
+
+ /**
+ * Whether to enable autocomplete for this parameter. If set to true, the bot will provide suggestions for this parameter based on user input.
+ */
boolean autocomplete() default false;
+
+ /**
+ * The {@link OptionType} of the parameter. This defines the data type of the parameter in the command interface (e.g. STRING, INTEGER, BOOLEAN, etc.).
+ * Default is STRING.
+ */
OptionType type() default OptionType.STRING;
}
diff --git a/src/main/java/botcommons/commands/ReplyContext.java b/src/main/java/botcommons/commands/ReplyContext.java
index 74aa8f7..248f818 100644
--- a/src/main/java/botcommons/commands/ReplyContext.java
+++ b/src/main/java/botcommons/commands/ReplyContext.java
@@ -77,6 +77,14 @@ public ReplyContext menu(String menuId, Object... args) {
return this;
}
+ /**
+ * Adds a listener for a specific event type that will only be called once.
+ * @param eventType The type of event to listen for. This should be a subclass of {@link GenericEvent}.
+ * @param filter A predicate to filter the events. This allows you to specify conditions for the events that should trigger the listener.
+ * @param listener The listener function that will be called when the event is received. This should be a function that takes an instance of the event type and returns Void.
+ * @return The current instance of {@link ReplyContext} for chaining.
+ * @param The type of the event to listen for. This should be a subclass of {@link GenericEvent}.
+ */
public ReplyContext listenOnce(Class eventType, Predicate filter, Function listener) {
once = new OnceListener<>(eventType, interactionEvent.getJDA(), filter, listener);
return this;
@@ -95,6 +103,11 @@ private void markAsFinished() {
this.once = null;
}
+ /**
+ * This method finalizes the reply context and sends the message to Discord. It will handle all the cases for sending a message, including:
+ * @param consumer A consumer that will be called with the resulting message after it has been sent. This allows you to perform additional actions on the message, such as logging or further processing.
+ * @return true if the reply was successfully sent, false otherwise. This method will also mark the reply context as finished.
+ */
public boolean finish(Consumer consumer) {
if (finished)
throw new IllegalStateException("ReplyContext already finished");
diff --git a/src/main/java/botcommons/config/Config.java b/src/main/java/botcommons/config/Config.java
index 384eeb9..ccdfda8 100644
--- a/src/main/java/botcommons/config/Config.java
+++ b/src/main/java/botcommons/config/Config.java
@@ -14,9 +14,10 @@ public class Config extends HashMap {
private static Config instance;
/**
- * Creates a config file with the given values and bot name
- * @param oldValues The values to put in the config
- * @return The {@link Config} object
+ * Creates a new Config instance from the provided old values and bot name.
+ * @param oldValues A map containing old values to be used in the configuration. This can include key-value pairs that will be added to the new config.
+ * @param botName The name of the bot for which the configuration is being created. This will be used to set the "bot-name" key in the configuration.
+ * @return Returns a new instance of the Config class, which is a HashMap containing the provided old values and additional default values.
*/
public static Config makeConfig(Map oldValues, String botName) {
HashMap values = new HashMap<>();
@@ -50,6 +51,12 @@ public static Config makeConfig(Map oldValues, String botName) {
return instance;
}
+ /**
+ * Creates a new Config instance from a JSON file.
+ * @param file The path to the JSON file from which to load the configuration. This file should contain a valid JSON representation of a Config object.
+ * @return Returns a Config object that has been populated with the data from the specified JSON file. This object will be an instance of the Config class, which extends HashMap.
+ * @throws IOException If an I/O error occurs while reading the file. This can happen if the file does not exist, is not accessible, or if there are issues with reading the file's contents.
+ */
public static Config makeConfig(String file) throws IOException {
Config config = new GsonBuilder().setPrettyPrinting().create()
.fromJson(Files.readString(new File(file).toPath()), Config.class);
@@ -86,6 +93,10 @@ public Object get(Object key) {
return get(key.toString(), String.class);
}
+ /**
+ * Writes the current configuration to a JSON file.
+ * @throws IOException If an I/O error occurs while writing to the file. This can happen if the file is not writable, the directory does not exist, or there are permission issues.
+ */
public void write() throws IOException {
Files.writeString(Path.of(Config.instance.get("bot-name") + "-assets", "config.json"), toString());
}
diff --git a/src/main/java/botcommons/config/ConfigManager.java b/src/main/java/botcommons/config/ConfigManager.java
index cd05ade..1247de9 100644
--- a/src/main/java/botcommons/config/ConfigManager.java
+++ b/src/main/java/botcommons/config/ConfigManager.java
@@ -34,26 +34,54 @@ public ConfigManager(String botName, JDA jda) {
instance = this;
}
+ /**
+ * Initializes the ConfigManager with a default configuration.
+ * @param config The default configuration to be used if no specific server configuration is found.
+ */
public void setDefault(Config config) {
configs.put("default", config);
}
+ /**
+ * Sets the config for a server, and writes it to a file.
+ * @param serverId The ID of the server for which the configuration is being set. This will be used to create a unique file for the server.
+ * @param config The configuration object to be set for the server. This object will be serialized to JSON and saved to a file named after the server ID.
+ */
public void setConfig(String serverId, Config config) {
configs.put(serverId, config);
writeConfigToFile(serverId, config);
}
+ /**
+ * Sets a specific value in the config for the server
+ * @param serverId The ID of the server for which the value is being set. This will determine which server's configuration will be updated.
+ * @param key The key under which the value will be stored in the configuration. This key will be used to retrieve the value later.
+ * @param value The value to be set in the configuration for the specified key. This can be any object, and it will be serialized to JSON when saved to the configuration file.
+ */
public void setValue(String serverId, String key, Object value) {
Config config = configs.getOrDefault(serverId, configs.get("default"));
config.put(key, value);
writeConfigToFile(serverId, config);
}
+ /**
+ * Retrieves a value from the configuration for a specific server.
+ * @param serverId The ID of the server for which the value is being retrieved. This will determine which server's configuration will be accessed.
+ * @param key The key for the value you want to retrieve from the configuration. This key should match the one used when setting the value.
+ * @param type The class type of the value you want to retrieve. This is used to deserialize the JSON value back into the appropriate Java type. For example, if you expect an Integer, you would pass Integer.class.
+ * @return The value associated with the specified key in the configuration for the given server. The return type will depend on the type parameter provided. If the key does not exist, it will return null.
+ * @param The type of the value to be returned. This is a generic type parameter that allows the method to return the value in the desired type. For example, if you expect an Integer, you would specify Integer.class when calling this method.
+ */
public T getValue(String serverId, String key, Class type) {
Config config = configs.getOrDefault(serverId, configs.get("default"));
return config.get(key, type);
}
+ /**
+ * Write the configuration to a file for a specific server.
+ * @param serverId The ID of the server for which the configuration is being written. This will be used to create a unique filename for the configuration file.
+ * @param config The configuration object to be written to the file. This object will be serialized to JSON and saved to a file named after the server ID.
+ */
private void writeConfigToFile(String serverId, Config config) {
final int MAX_RETRIES = 3;
int attempts = 0;
@@ -108,6 +136,8 @@ public void onGuildReady(@NotNull GuildReadyEvent event) {
} else {
configs.put(serverId, configs.get("default"));
}
+
+ writeConfigToFile(serverId, configs.get(serverId));
}
}
diff --git a/src/main/java/botcommons/menu/MenuManager.java b/src/main/java/botcommons/menu/MenuManager.java
index b93bf45..ce7c5fb 100644
--- a/src/main/java/botcommons/menu/MenuManager.java
+++ b/src/main/java/botcommons/menu/MenuManager.java
@@ -22,12 +22,20 @@ public class MenuManager extends ListenerAdapter {
public static MenuManager instance;
+ /**
+ * Creates a new instance of {@link MenuManager}. This will register the instance with JDA and add itself as an event listener.
+ * @param jda The JDA instance to register with. This allows the manager to listen for button interactions.
+ */
public MenuManager(JDA jda) {
instance = this;
this.jda = jda;
jda.addEventListener(this);
}
+ /**
+ * Registers one or more menus to the menu registry. This allows the manager to handle button interactions for these menus.
+ * @param menus The menus to register. Each menu should be annotated with {@link botcommons.menu.Menu} to provide an ID.
+ */
public static void registerMenu(IMenu... menus) {
for (IMenu menu : menus) {
String menuId = menu.getClass().getAnnotation(Menu.class).id();
@@ -36,6 +44,11 @@ public static void registerMenu(IMenu... menus) {
}
}
+ /**
+ * Registers a menu with a specific ID. This allows for dynamic registration of menus that may not be known at compile time.
+ * @param id The ID to register the menu with. This should be a unique identifier for the menu.
+ * @param menu The menu instance to register. This should implement the {@link IMenu} interface and provide the necessary functionality for handling button interactions.
+ */
public static void registerMenuWithId(String id, IMenu menu) {
if (id == null || id.isEmpty()) {
throw new IllegalArgumentException("Menu ID cannot be null or empty");
@@ -46,6 +59,11 @@ public static void registerMenuWithId(String id, IMenu menu) {
menuRegistry.put(id, menu);
}
+ /**
+ * Sends a menu to a specific text channel. This method builds the menu's embed and sends it as a message to the specified channel.
+ * @param menuId The ID of the menu to send
+ * @param channelId The channel to send it in
+ */
public static void sendMenu(String menuId, String channelId) {
IMenu menu = menuRegistry.get(menuId);
@@ -62,6 +80,11 @@ public static void sendMenu(String menuId, String channelId) {
.queue(message -> menu.setMessageId(message.getId()));
}
+ /**
+ * Sends a menu to a user's private channel. This method builds the menu's embed and sends it as a private message to the specified user.
+ * @param menuId The ID of the menu to send. This should correspond to a registered menu in the {@link MenuManager#menuRegistry}.
+ * @param userId The ID of the user to send the menu to. This should be a valid Discord user ID. The method will attempt to retrieve the user and send the private message.
+ */
public static void sendMenuPrivate(String menuId, String userId) {
IMenu menu = menuRegistry.get(menuId);
@@ -100,6 +123,12 @@ public static void replyMenu(String menuId, Message message, Object... args) {
menu.setMessageId(message1.getId()));
}
+ /**
+ * Replies to a message with a menu. This method builds the menu's embed and sends it as a reply to the specified interaction hook.
+ * @param menuId The ID of the menu to send. This should correspond to a registered menu in the {@link MenuManager#menuRegistry}.
+ * @param hook The interaction hook to reply to. This is typically obtained from a slash command interaction or button interaction. It allows you to send a message in response to the interaction.
+ * @param args The arguments to pass into constructing the menu instance. This allows for dynamic creation of menus based on runtime parameters. The arguments should match the constructor of the menu class if it has one.
+ */
public static void replyMenu(String menuId, InteractionHook hook, Object... args) {
IMenu menu = getMenu(menuId, args);
diff --git a/src/main/java/botcommons/menu/types/PageMenu.java b/src/main/java/botcommons/menu/types/PageMenu.java
index bb11888..ff82fc0 100644
--- a/src/main/java/botcommons/menu/types/PageMenu.java
+++ b/src/main/java/botcommons/menu/types/PageMenu.java
@@ -61,7 +61,8 @@ public MessageEmbed build() {
public Button[] getButtons() {
return new Button[]{
Button.of(ButtonStyle.PRIMARY, "left", Emoji.fromUnicode("⬅️")),
- Button.of(ButtonStyle.SECONDARY, "right", Emoji.fromUnicode("➡️"))
+ Button.of(ButtonStyle.SECONDARY, "right", Emoji.fromUnicode("➡️")),
+ Button.of(ButtonStyle.DANGER, "end", Emoji.fromUnicode("❌"))
};
}
}
diff --git a/src/main/java/botcommons/utilities/JsonUtils.java b/src/main/java/botcommons/utilities/JsonUtils.java
index 1858651..5c33286 100644
--- a/src/main/java/botcommons/utilities/JsonUtils.java
+++ b/src/main/java/botcommons/utilities/JsonUtils.java
@@ -16,7 +16,13 @@
import java.nio.file.Path;
import java.util.HashMap;
+/**
+ * Utility class for handling JSON serialization and deserialization using Gson.
+ */
public class JsonUtils {
+ /**
+ * The Gson instance used for JSON serialization and deserialization.
+ */
private static final Gson GSON = new GsonBuilder()
.setExclusionStrategies(new ExclusionStrategy() {
@Override
@@ -35,6 +41,13 @@ public boolean shouldSkipClass(Class> clazz) {
.create();
+ /**
+ * Create a cache file from a HashMap if it does not already exist.
+ * @param map The HashMap to serialize into a JSON file. This map will be converted to JSON and saved to a file.
+ * @param name The name of the cache file to be created. This name will be used to create the file path where the JSON data will be stored. The file will be saved in the "cache" directory with a ".json" extension.
+ * @param The key type
+ * @param The value type
+ */
public static void createCache(HashMap map, String name) {
File file = StringUtilities.getAssetPath(Path.of("cache/",name+".json")).toFile();
if (file.exists()) return;
@@ -46,6 +59,11 @@ public static void createCache(HashMap map, String name) {
}
}
+ /**
+ * Updates the cache file with the contents of the provided HashMap. If the cache file does not exist, it will be created.
+ * @param map The HashMap to serialize into a JSON file. This map will be merged with existing data in the cache file if it exists.
+ * @param name The name of the cache file to be updated. This name will be used to create the file path where the JSON data will be stored. The file will be saved in the "cache" directory with a ".json" extension.
+ */
public static void updateCache(HashMap, ?> map, String name) {
Logger logger = LoggerFactory.getLogger(JsonUtils.class);
File file = StringUtilities.getAssetPath(Path.of("cache/", name + ".json")).toFile();
diff --git a/src/main/java/botcommons/utilities/StringUtilities.java b/src/main/java/botcommons/utilities/StringUtilities.java
index 27c3642..145fb96 100644
--- a/src/main/java/botcommons/utilities/StringUtilities.java
+++ b/src/main/java/botcommons/utilities/StringUtilities.java
@@ -15,12 +15,27 @@ public class StringUtilities {
public static String botName = "default";
static Logger logger = LoggerFactory.getLogger(StringUtilities.class);
+ /**
+ * This method converts a HashMap with generic keys and values to a HashMap with String keys and String values by serializing each key and value to JSON format.
+ * @param map The input HashMap with generic keys and values. This map can contain any type of objects as keys and values.
+ * @return A new {@link HashMap} where each key and value from the input map has been serialized to a JSON string. This allows for easy storage or transmission of the map's contents in a standardized format.
+ */
public static HashMap stringifyMap(HashMap, ?> map) {
HashMap stringMap = new HashMap<>();
Gson gson = new GsonBuilder().setPrettyPrinting().create();
map.forEach((key, value) -> stringMap.put(gson.toJson(key), gson.toJson(value)));
return stringMap;
}
+
+ /**
+ * This method parses a HashMap of String keys and String values back into a Map with specified key and value types using Gson for deserialization.
+ * @param strings The input HashMap with String keys and String values. This map is expected to contain JSON strings that represent the keys and values of the desired output map.
+ * @param keyClass The class type of the keys in the output map. This parameter specifies the type to which the keys in the input map should be deserialized. For example, if you want the keys to be integers, you would pass Integer.class.
+ * @param valueClass The class type of the values in the output map. This parameter specifies the type to which the values in the input map should be deserialized. For example, if you want the values to be strings, you would pass String.class or if you want them to be integers, you would pass Integer.class.
+ * @return A new {@link Map} where each key and value from the input HashMap has been deserialized into the specified types. The keys and values in the output map will be of the types specified by the keyClass and valueClass parameters, respectively. This allows for type-safe access to the elements in the resulting map.
+ * @param The type of the keys in the output map. This is a generic type parameter that allows the method to return a map with keys of the specified type. For example, if you want the keys to be integers, you would specify Integer.class when calling this method.
+ * @param The type of the values in the output map. This is a generic type parameter that allows the method to return a map with values of the specified type. For example, if you want the values to be strings, you would specify String.class when calling this method, or if you want them to be integers, you would specify Integer.class.
+ */
@SuppressWarnings("unused")
public static Map parseMap(HashMap strings, Class keyClass, Class valueClass) {
HashMap map = new HashMap<>();
@@ -29,6 +44,11 @@ public static Map parseMap(HashMap strings, Class