package wtf.beatrice.hidekobot.runnables; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; import net.dv8tion.jda.api.entities.emoji.Emoji; import net.dv8tion.jda.api.interactions.components.buttons.Button; import org.json.JSONObject; import wtf.beatrice.hidekobot.Cache; import wtf.beatrice.hidekobot.commands.base.Trivia; import wtf.beatrice.hidekobot.objects.comparators.TriviaScoreComparator; import wtf.beatrice.hidekobot.objects.fun.TriviaCategory; import wtf.beatrice.hidekobot.objects.fun.TriviaQuestion; import wtf.beatrice.hidekobot.objects.fun.TriviaScore; import wtf.beatrice.hidekobot.services.CommandService; import wtf.beatrice.hidekobot.services.DatabaseService; import java.util.*; import java.util.concurrent.ScheduledFuture; public class TriviaTask implements Runnable { private final DatabaseService databaseService; private final CommandService commandService; private final User author; private final MessageChannel channel; private Message previousMessage = null; private final JSONObject triviaJson; private final List questions; private final TriviaCategory category; ScheduledFuture future = null; private int iteration = 0; public TriviaTask(User author, MessageChannel channel, TriviaCategory category, DatabaseService databaseService, CommandService commandService) { this.author = author; this.channel = channel; this.category = category; this.databaseService = databaseService; this.commandService = commandService; triviaJson = Trivia.fetchJson(Trivia.getTriviaLink(category.categoryId())); questions = Trivia.parseQuestions(triviaJson); //todo: null check, rate limiting... } public void setScheduledFuture(ScheduledFuture future) { this.future = future; } @Override public void run() { if (previousMessage != null) { // todo: we shouldn't use this method, since it messes with the database... look at coin reflip commandService.disableExpired(previousMessage.getId()); String previousCorrectAnswer = questions.get(iteration - 1).correctAnswer(); // we need this to be thread-locking to avoid getting out of sync with the rest of the trivia features previousMessage.reply("The correct answer was: **" + previousCorrectAnswer + "**!").complete(); // todo: maybe also add who replied correctly as a list // clean the list of people who answered, so they can answer again for the new question Trivia.channelAndWhoResponded.put(previousMessage.getChannel().getId(), new ArrayList<>()); } if (iteration >= questions.size()) { String scoreboardText = "\uD83D\uDC23 Trivia session is over!"; List winners = new ArrayList<>(); int topScore = 0; StringBuilder othersBuilder = new StringBuilder(); LinkedList triviaScores = Trivia.channelAndScores.get(channel.getId()); if (triviaScores == null) triviaScores = new LinkedList<>(); else triviaScores.sort(new TriviaScoreComparator()); int pos = 0; Integer previousScore = null; for (TriviaScore triviaScore : triviaScores) { if (pos > 10) break; // cap at top 10 String user = triviaScore.getUser().getAsMention(); int score = triviaScore.getScore(); if (previousScore == null) { previousScore = score; topScore = score; pos = 1; } else { if (score != previousScore) pos++; } if (pos == 1) winners.add(user); else { othersBuilder.append("\n").append(pos) .append(" | ").append(user) .append(": ").append(score).append(" points"); } } StringBuilder winnersBuilder = new StringBuilder(); for (int i = 0; i < winners.size(); i++) { String winner = winners.get(i); winnersBuilder.append(winner); if (i + 1 != winners.size()) { winnersBuilder.append(", "); // separate with comma except on last run } else { winnersBuilder.append(": ").append(topScore).append(" points \uD83C\uDF89"); } } String winnersTitle = "\uD83D\uDCAB "; winnersTitle += winners.size() == 1 ? "Winner" : "Winners"; String winnersString = winnersBuilder.toString(); String othersString = othersBuilder.toString(); EmbedBuilder scoreboardBuilder = new EmbedBuilder(); scoreboardBuilder.setColor(Cache.getBotColor()); scoreboardBuilder.setTitle("\uD83C\uDF1F Trivia Scoreboard"); if (!winnersString.isEmpty()) scoreboardBuilder.addField(winnersTitle, winnersString, false); else scoreboardBuilder.addField("\uD83D\uDE22 Sad Trivia", "No one played \uD83D\uDE2D", false); if (!othersString.isEmpty()) scoreboardBuilder.addField("☁️ Others", othersString, false); channel.sendMessage(scoreboardText).addEmbeds(scoreboardBuilder.build()).queue(); // remove all cached data Trivia.channelsRunningTrivia.remove(channel.getId()); Trivia.channelAndWhoResponded.remove(channel.getId()); Trivia.channelAndScores.remove(channel.getId()); future.cancel(false); // we didn't implement null checks on the future on purpose, because we need to know if we were unable // to cancel it (and console errors should make it clear enough). return; } TriviaQuestion currentTriviaQuestion = questions.get(iteration); List