diff --git a/jdac/src/main/java/com/github/kaktushose/jda/commands/JDACommands.java b/jdac/src/main/java/com/github/kaktushose/jda/commands/JDACommands.java index 331f1332..abc86606 100644 --- a/jdac/src/main/java/com/github/kaktushose/jda/commands/JDACommands.java +++ b/jdac/src/main/java/com/github/kaktushose/jda/commands/JDACommands.java @@ -124,34 +124,34 @@ public void updateGuildCommands() { updater.updateGuildCommands(); } - /// Gets a [`Button`][com.github.kaktushose.jda.commands.annotations.interactions.Button] based on the definition id - /// and transforms it into a JDA [Button]. + /// Gets a [`Button`][com.github.kaktushose.jda.commands.annotations.interactions.Button] based on the method name + /// and the given class and transforms it into a JDA [Button]. /// - /// The button will be [`Runtime`]({@docRoot}/index.html#runtime-concept-heading) independent. This may be useful if you want to send a message without - /// using the framework. + /// The button will be [`Runtime`]({@docRoot}/index.html#runtime-concept-heading) independent. + /// This may be useful if you want to send a message without using the framework. /// /// @param button the name of the button in the format `FullClassNameWithPackage.method`` /// @return the JDA [Button] @NotNull - public Button getButton(@NotNull String button) { - var id = String.valueOf(button.replaceAll("\\.", "").hashCode()); + public Button getButton(@NotNull Class origin, @NotNull String button) { + var id = String.valueOf((origin.getName() + button).hashCode()); var definition = interactionRegistry.find(ButtonDefinition.class, false, it -> it.definitionId().equals(id)); return definition.toJDAEntity(CustomId.independent(definition.definitionId())); } - /// Gets a [StringSelectMenu] or [EntitySelectMenu] based on the definition id and transforms it into a JDA [SelectMenu]. + /// Gets a [StringSelectMenu] or [EntitySelectMenu] based on the method name and the given class and transforms it + /// into a JDA [SelectMenu]. /// - /// The select menu will be [`Runtime`]({@docRoot}/index.html#runtime-concept-heading) independent. This may be useful if you want to send a component - /// without using the framework. + /// The select menu will be [`Runtime`]({@docRoot}/index.html#runtime-concept-heading) independent. + /// This may be useful if you want to send a component without using the framework. /// + /// @param origin the [Class] of the method /// @param menu the name of the button in the format `FullClassNameWithPackage.method`` /// @return the JDA [SelectMenu] - @SuppressWarnings("unchecked") @NotNull - public SelectMenu getSelectMenu(@NotNull String menu) { - var id = String.valueOf(menu.replaceAll("\\.", "").hashCode()); + public SelectMenu getSelectMenu(@NotNull Class origin, @NotNull String menu) { + var id = String.valueOf((origin.getName() + menu).hashCode()); var definition = interactionRegistry.find(SelectMenuDefinition.class, false, it -> it.definitionId().equals(id)); return (SelectMenu) definition.toJDAEntity(CustomId.independent(definition.definitionId())); } - } diff --git a/jdac/src/main/java/com/github/kaktushose/jda/commands/dispatching/events/ReplyableEvent.java b/jdac/src/main/java/com/github/kaktushose/jda/commands/dispatching/events/ReplyableEvent.java index 4bf377ea..3745cd28 100644 --- a/jdac/src/main/java/com/github/kaktushose/jda/commands/dispatching/events/ReplyableEvent.java +++ b/jdac/src/main/java/com/github/kaktushose/jda/commands/dispatching/events/ReplyableEvent.java @@ -2,6 +2,7 @@ import com.github.kaktushose.jda.commands.annotations.interactions.EntitySelectMenu; import com.github.kaktushose.jda.commands.annotations.interactions.StringSelectMenu; +import com.github.kaktushose.jda.commands.definitions.features.CustomIdJDAEntity; import com.github.kaktushose.jda.commands.definitions.interactions.CustomId; import com.github.kaktushose.jda.commands.definitions.interactions.InteractionDefinition; import com.github.kaktushose.jda.commands.definitions.interactions.InteractionRegistry; @@ -18,10 +19,12 @@ import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.events.interaction.GenericInteractionCreateEvent; import net.dv8tion.jda.api.interactions.callbacks.IReplyCallback; +import net.dv8tion.jda.api.interactions.components.ActionComponent; import net.dv8tion.jda.api.interactions.components.buttons.Button; import net.dv8tion.jda.api.interactions.components.selections.SelectMenu; import net.dv8tion.jda.api.utils.messages.MessageCreateData; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -82,13 +85,25 @@ public void removeComponents() { /// The button will be linked to the current [`Runtime`]({@docRoot}/index.html#runtime-concept-heading). /// This may be useful if you want to send a component without using the framework. /// - /// @param button the name of the button + /// @param button the name of the button defining method /// @return the JDA [Button] @NotNull public Button getButton(@NotNull String button) { - var id = String.valueOf(("%s%s".formatted(definition.clazzDescription().name(), button)).hashCode()); - var definition = registry.find(ButtonDefinition.class, false, it -> it.definitionId().equals(id)); - return definition.toJDAEntity(new CustomId(runtimeId(), definition.definitionId())); + return getComponent(button, null, ButtonDefinition.class); + } + + /// Gets a [`Button`][com.github.kaktushose.jda.commands.annotations.interactions.Button] based on the method name + /// and the given class and transforms it into a JDA [Button]. + /// + /// The button will be [`runtime`]({@docRoot}/index.html#runtime-concept-heading)-independent. + /// This may be useful if you want to send a component without using the framework. + /// + /// @param origin the [Class] of the method + /// @param button the name of the button defining method + /// @return the JDA [Button] + @NotNull + public Button getButton(@NotNull Class origin, @NotNull String button) { + return getComponent(button, null, ButtonDefinition.class); } /// Gets a [StringSelectMenu] or [EntitySelectMenu] based on the method name and transforms it into a JDA [SelectMenu]. @@ -100,9 +115,29 @@ public Button getButton(@NotNull String button) { /// @return the JDA [SelectMenu] @NotNull public SelectMenu getSelectMenu(@NotNull String menu) { - var id = String.valueOf(("%s%s".formatted(definition.clazzDescription().name(), menu)).hashCode()); - var definition = registry.find(SelectMenuDefinition.class, false, it -> it.definitionId().equals(id)); - return (SelectMenu) definition.toJDAEntity(new CustomId(runtimeId(), definition.definitionId())); + return getComponent(menu, null, SelectMenuDefinition.class); + } + + /// Gets a [StringSelectMenu] or [EntitySelectMenu] based on the method name and transforms it into a JDA [SelectMenu]. + /// + /// The select menu will be [`runtime`]({@docRoot}/index.html#runtime-concept-heading)-independent. + /// This may be useful if you want to send a component without using the framework. + /// + /// @param origin the [Class] of the method + /// @param menu the name of the select menu + /// @return the JDA [SelectMenu] + @NotNull + public SelectMenu getSelectMenu(@NotNull Class origin, @NotNull String menu) { + return getComponent(menu, origin, SelectMenuDefinition.class); + } + + @NotNull + @SuppressWarnings("unchecked") + private > C getComponent(@NotNull String component, @Nullable Class origin, @NotNull Class type) { + var className = origin == null ? definition.clazzDescription().name() : origin.getName(); + var id = String.valueOf((className + component).hashCode()); + var definition = registry.find(type, false, it -> it.definitionId().equals(id)); + return (C) definition.toJDAEntity(new CustomId(runtimeId(), definition.definitionId())); } /// Entry point for configuring a reply. diff --git a/jdac/src/main/java/com/github/kaktushose/jda/commands/dispatching/reply/Component.java b/jdac/src/main/java/com/github/kaktushose/jda/commands/dispatching/reply/Component.java index 2415d304..fcabf69c 100644 --- a/jdac/src/main/java/com/github/kaktushose/jda/commands/dispatching/reply/Component.java +++ b/jdac/src/main/java/com/github/kaktushose/jda/commands/dispatching/reply/Component.java @@ -3,6 +3,8 @@ import com.github.kaktushose.jda.commands.annotations.interactions.Button; import com.github.kaktushose.jda.commands.annotations.interactions.EntitySelectMenu; import com.github.kaktushose.jda.commands.annotations.interactions.StringSelectMenu; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /// Represents a component, namely [Button], [StringSelectMenu] or [EntitySelectMenu], that should be added to a reply. /// @@ -23,9 +25,9 @@ /// event.with().components(Components.of(true, false, "onButton")).reply(); /// } ///``` -public record Component(boolean enabled, boolean independent, String name) { +public record Component(boolean enabled, boolean independent, @NotNull String name, @Nullable Class origin) { - /// Adds enabled, runtime-bound [Component]s to the reply. + /// Adds an enabled, runtime-bound [Component] to the reply. /// /// @param component the name of the method that represents the component public static Component enabled(String component) { @@ -39,7 +41,7 @@ public static Component disabled(String component) { return of(false, false, component); } - /// Adds enabled, runtime-independent [Component]s to the reply. + /// Adds an enabled, runtime-independent [Component] to the reply. /// /// Every component interaction will create a new [`Runtime`]({@docRoot}/index.html#runtime-concept-heading). Furthermore, the component cannot expire and /// will always get executed, even after a bot restart. @@ -49,12 +51,40 @@ public static Component independent(String component) { return of(true, true, component); } + /// Adds an enabled [Component] to the reply that is defined in a different class. This [Component] will always be + /// runtime-independent. + /// + /// @param origin the [Class] the `component` is defined in + /// @param component the name of the method that represents the component + public static Component enabled(Class origin, String component) { + return of(true, origin, component); + } + + /// Adds a disabled [Component] to the reply that is defined in a different class. This [Component] will always be + /// runtime-independent. + /// + /// @param origin the [Class] the `component` is defined in + /// @param component the name of the method that represents the component + public static Component disabled(Class origin, String component) { + return of(false, origin, component); + } + /// Adds [Component]s with the passed configuration to the reply. /// /// @param enabled whether the [Component] should be enabled or disabled /// @param independent whether the [Component] should be runtime-bound or independent - /// @param component the name of the method that represents the component + /// @param component the name of the method that represents the component public static Component of(boolean enabled, boolean independent, String component) { - return new Component(enabled, independent, component); + return new Component(enabled, independent, component, null); } + + /// Adds [Component]s with the passed configuration to the reply. + /// + /// @param enabled whether the [Component] should be enabled or disabled + /// @param origin the [Class] the `component` is defined in + /// @param component the name of the method that represents the component + public static Component of(boolean enabled, Class origin, String component) { + return new Component(enabled, true, component, origin); + } + } diff --git a/jdac/src/main/java/com/github/kaktushose/jda/commands/dispatching/reply/ConfigurableReply.java b/jdac/src/main/java/com/github/kaktushose/jda/commands/dispatching/reply/ConfigurableReply.java index ac937b2e..8015278c 100644 --- a/jdac/src/main/java/com/github/kaktushose/jda/commands/dispatching/reply/ConfigurableReply.java +++ b/jdac/src/main/java/com/github/kaktushose/jda/commands/dispatching/reply/ConfigurableReply.java @@ -183,7 +183,10 @@ public ComponentReply components(@NotNull String... components) { public ComponentReply components(@NotNull Component... components) { List items = new ArrayList<>(); for (Component component : components) { - var definitionId = String.valueOf((definition.methodDescription().declaringClass().getName() + component.name()).hashCode()); + var className = component.origin() == null + ? definition.methodDescription().declaringClass().getName() + : component.origin().getName(); + var definitionId = String.valueOf((className + component.name()).hashCode()); var definition = registry.find(ComponentDefinition.class, false, it -> it.definitionId().equals(definitionId) );