Search code examples
javaevent-handlingdiscordaudio-playerdiscord-jda

Issues while implementing a vote skip command for my JDA Music Bot


This is my first time asking a question here, so please excuse any mistakes I do while posting this. Also I'm somewhat new to programming, so please excuse any bad practices I do as well.

So what I'm trying to do is to create a vote skip command to skip the current song for my JDA Discord music bot. My issue is that I can't find a way to count the votes (in this case reactions added on a message sent by my bot).

The following code snippet shows what I attempted:

channel.sendMessage( builder.build() ).queue( (message) -> {
            message.addReaction(Emojis.upvote).queue();
            message.addReaction(Emojis.downvote).queue();

            this.waiter.waitForEvent(
                    
                    // The class the EventWaiter should listen for
                    GuildMessageReactionAddEvent.class,
                    
                    // Conditions
                    
                    // TODO Change event as GuildMessageReactionAddEvent doesn't provide a count for reactions
                    (evt) -> ((GuildMessageReactionAddEvent) evt).getReaction().getCount() >= 10
                    
                            && ((GuildMessageReactionAddEvent) evt).getReaction().getReactionEmote().getEmoji().equals(Emojis.upvote)
                            && evt.getMessageIdLong() == context.getMessage().getIdLong(),
                    
                    // Action if the conditions are fulfilled
                    (evt) -> skip(context),
                    
                    // Timeout after 1 minute
                    1L, TimeUnit.MINUTES,
                    
                    // Action after timeout
                    () -> channel.sendMessage("Not enough votes! Track will be continued").queue());
        } );

I realized that GuildMessageReactionAddEvent doesn't provide a count for reactions on the message, because it only checks for a single reaction added to the message, meaning that my attempt makes no sense at all.

My idea for a solution to this problem is to use an int variable as a counter that increments each time the GuildMessageReactionAddEvent event is fired. Now, as soon as the counter reaches the required amount of votes, the song is skipped, if not, there will be a timeout resulting in the bot sending the "Not enough votes!" message.

I would really appreciate if some of you could write some suggestions or just hints, as to how to solve this problem.


Solution

  • You'll need to do something like this (this is a sketch, not compileable code)

    You need to record the number of votes, so your predicate needs to have a side effect.

    You can do this with an AtomicInteger in the scope of the predicate lambda.

    The return value of the predicate depends on the number of votes.

           channel.sendMessage( builder.build() ).queue( (message) -> {
                final AtomicInteger voteCounter = new AtomicInteger();
                message.addReaction(Emojis.upvote).queue();
                message.addReaction(Emojis.downvote).queue();
    
                this.waiter.waitForEvent(
    
                        // The class the EventWaiter should listen for
                        GuildMessageReactionAddEvent.class,
    
                        // Conditions
    
                        (evt) -> {
                            if (((GuildMessageReactionAddEvent) evt).getReaction().getReactionEmote().getEmoji().equals(Emojis.upvote)
                                && evt.getMessageIdLong() == context.getMessage().getIdLong()) {
                                voteCounter.incrementAndGet();
                            }
                            return voteCounter.get() > 10;
                        },
    
                        // Action if the conditions are fullfilled
                        (evt) -> skip(context),
    
                        // Timeout after 1 minute
                        1L, TimeUnit.MINUTES,
    
                        // Action after timeout
                        () -> channel.sendMessage("Not enough votes! Track will be continued").queue());
            } );
        }