Skip to content

Commit

Permalink
Achievements (#82)
Browse files Browse the repository at this point in the history
* dailies need to use usersV2

* WIP: achievemnts v1

* added pagination action row

* achievementslist, achievemnt commands. Make achievements work when a
test is submitted.

* chore: gitignore cache, unhide ZBotData

* bugfix: fix name of button

* chore: docs, code style fixes

* chore: more docs

* chore: even more docs

* chore: remove logs

* bugfix: fix up file paths
  • Loading branch information
VanillaViking authored Sep 30, 2023
1 parent 9da7f23 commit a2e93d5
Show file tree
Hide file tree
Showing 15 changed files with 471 additions and 22 deletions.
5 changes: 1 addition & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,10 @@ target/
debug/
test/
.vim/
ZBotData/
ZBotData/cache/
bin/

# Files
*.zbif
*.zbsf
*.zbo
*.log
*.prefs
credentials.json
Expand Down
51 changes: 51 additions & 0 deletions src/main/java/asynchronous/typing/Achievement.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package asynchronous.typing;

import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.MessageChannel;
import zyenyo.Database;

import java.awt.Color;
import java.io.File;
import java.util.Arrays;

import dataStructures.AchievementDetails;
import dataStructures.streakStatusResult;

public class Achievement implements Runnable {
private MessageReceivedEvent event;
private String idStr;
private MessageChannel channel;
private String[] args;

public Achievement(MessageReceivedEvent event, String[] args) {
this.event = event;
this.idStr = event.getAuthor().getId();
this.channel = event.getChannel();
this.args = args;
}

@Override
public void run() {
event.getChannel().sendTyping().queue();
try {
AchievementDetails achievement = Database.getAchievement(String.join(" ", Arrays.copyOfRange(args, 1, args.length)));
EmbedBuilder embed = new EmbedBuilder().setColor(Color.black);

embed.setTitle(achievement.title());

embed.setThumbnail(String.format("attachment://thumbnail.png"));
embed.setDescription(achievement.description());

File file = new File(achievement.thumbnail());


channel.sendMessageEmbeds(embed.build()).addFile(file, "thumbnail.png").queue();

} catch (Exception e) {
System.err.println(e);
}

}

}
101 changes: 101 additions & 0 deletions src/main/java/asynchronous/typing/AchievementList.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package asynchronous.typing;

import net.dv8tion.jda.api.events.interaction.ButtonClickEvent;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.interactions.components.Button;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.Emoji;
import net.dv8tion.jda.api.entities.MessageChannel;
import zyenyo.Database;

import java.awt.Color;
import java.util.Arrays;

import org.bson.Document;

import com.mongodb.client.AggregateIterable;

public class AchievementList implements Runnable {
// limit on the number button clicks allowed, so that users don't keep bumping old messages and send unnecessary calls to the bot
private static final Integer BUTTONCLICK_MAX = 50;
private MessageReceivedEvent event;
private MessageChannel channel;
// TODO: using a static variable for pages causes problems when a user interacts with multiple messages of the same command.
static Integer page;
static Integer buttonClickCount;

public AchievementList(MessageReceivedEvent event, String[] args) {
this.event = event;
this.channel = event.getChannel();
}

@Override
public void run() {
event.getChannel().sendTyping().queue();
page = 1;
buttonClickCount = 0;

try {

EmbedBuilder embed = makeAchievementList();

channel.sendMessageEmbeds(embed.build())
.setActionRow(
Button.secondary("achievementListPrev", Emoji.fromUnicode("U+25C0")).asDisabled(), // arrow backward
Button.secondary("achievementListNext", Emoji.fromUnicode("U+25B6")) // arrow forward
)
.queue();

} catch (Exception e) {
System.err.println(e);
}

}

private static EmbedBuilder makeAchievementList() {

AggregateIterable<Document> achievementList = Database.getAchievementList(page);
final int initialPosition = (page -1) * 10;

EmbedBuilder embed = new EmbedBuilder().setColor(Color.black);
embed.setTitle("Zyenyo Achievements");

int index = initialPosition;

for (Document doc : achievementList) {
embed.addField(String.format("[%d] %s", ++index, doc.getString("title")), doc.getString("description"), false);
}

embed.setFooter(
String.format("Showing achievements %d to %d on page %d.",
initialPosition+1, initialPosition+10, page)
);

return embed;
}

public static void onNextPage(ButtonClickEvent event) {
page++;
buttonClickCount++;

event.editMessageEmbeds(makeAchievementList().build())
.setActionRow(
Button.secondary("achievementListPrev", Emoji.fromUnicode("U+25C0")).withDisabled(page <=1 || buttonClickCount >= BUTTONCLICK_MAX), // arrow backward
Button.secondary("achievementListNext", Emoji.fromUnicode("U+25B6")).withDisabled(page >= 20 || buttonClickCount >= BUTTONCLICK_MAX) // arrow forward
)
.queue();
}

public static void onPrevPage(ButtonClickEvent event) {
page--;
buttonClickCount++;

event.editMessageEmbeds(makeAchievementList().build())
.setActionRow(
Button.secondary("achievementListPrev", Emoji.fromUnicode("U+25C0")).withDisabled(page <=1 || buttonClickCount >= BUTTONCLICK_MAX), // arrow backward
Button.secondary("achievementListNext", Emoji.fromUnicode("U+25B6")).withDisabled(page >= 20 || buttonClickCount >= BUTTONCLICK_MAX) // arrow forward
)
.queue();
}

}
2 changes: 1 addition & 1 deletion src/main/java/asynchronous/typing/TypeList.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
public class TypeList implements Runnable
{
private static final int NUM_PAGES = (BotConfig.NUM_PROMPTS / 10) + 1;
private static final String TEST_PROMPTS_FILEPATH = "ZBotData/TypingPrompts/";
private static final String TEST_PROMPTS_FILEPATH = "ZBotData/cache/TypingPrompts/";
private MessageReceivedEvent event;
private String[] args;

Expand Down
31 changes: 30 additions & 1 deletion src/main/java/asynchronous/typing/TypingTestTemplate.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package asynchronous.typing;

import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.Executors;
Expand All @@ -10,6 +11,7 @@
import org.apache.commons.text.similarity.LevenshteinDistance;

import commands.Typing;
import dataStructures.AchievementDetails;
import dataStructures.AddTestResult;
import dataStructures.TypingSubmission;
import dataStructures.TypingTestLeaderboard;
Expand All @@ -36,14 +38,18 @@ public abstract class TypingTestTemplate extends ListenerAdapter implements Runn
protected TypingTestLeaderboard submissions = new TypingTestLeaderboard();
protected String promptTitle;

protected final static String TEST_PROMPTS_FILEPATH = BotConfig.BOT_DATA_FILEPATH + "TypingPrompts/";
protected final static String TEST_PROMPTS_FILEPATH = BotConfig.BOT_DATA_FILEPATH + "cache/TypingPrompts/";
protected final static String ZERO_WIDTH_NON_JOINER = "‌";
protected final static short NUM_CHARS_IN_WORD = 5;

protected ScheduledExecutorService schedulePool = Executors.newSingleThreadScheduledExecutor();
protected Future<?> scheduledStop;


/**
* @param event : jda message event
* @param args : args that have been passed in to this command
*/
public TypingTestTemplate(MessageReceivedEvent event, String[] args)
{
this.event = event;
Expand Down Expand Up @@ -206,10 +212,16 @@ public void run()
embed.setTitle("Stopped Typing");
embed.setDescription("Hint, you can choose your prompt with \\TypeList");
}

HashMap<String, List<AchievementDetails>> achievementsUsers = new HashMap<>();

for (int i = 0; i < submissions.getNumSubmissions(); i++)
{
TypingSubmission s = submissions.getSubmission(lbOrder.get(i));
AddTestResult result = Database.addTestV2(s);

if (result.achievements().size() > 0) achievementsUsers.put(s.userTag(), result.achievements());

String dailyStreak = "";
if (result.dailyStreak() > 0) {
dailyStreak = String.format("Daily Streak: **`%d`**", result.dailyStreak());
Expand All @@ -228,6 +240,23 @@ public void run()
}
message.replyEmbeds(embed.build()).queue();
Typing.guildTestList.remove(event.getGuild().getIdLong());

if (achievementsUsers.isEmpty()) return;

for (String user : achievementsUsers.keySet()) {
List<AchievementDetails> achievementList = achievementsUsers.get(user);

EmbedBuilder achievementEmbed = new EmbedBuilder().setTitle(String.format("Achievements Unlocked for %s", user));
for (AchievementDetails achievement : achievementList) {
achievementEmbed.addField(achievement.title(), achievement.description(), false);
achievementEmbed.setThumbnail("attachment://thumbnail.png");
}

// use the first achievement image only since we can't put more than 1 thumbnail on an embed
File file = new File(achievementList.get(0).thumbnail());
channel.sendMessageEmbeds(achievementEmbed.build()).addFile(file, "thumbnail.png").queue();

}

}
};
Expand Down
25 changes: 25 additions & 0 deletions src/main/java/commands/Typing.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import java.util.HashMap;

import asynchronous.typing.Achievement;
import asynchronous.typing.AchievementList;
import asynchronous.typing.Chart;
import asynchronous.typing.Daily;
import asynchronous.typing.Leaderboard;
Expand All @@ -15,6 +17,7 @@
import dataStructures.InfoCard;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.MessageChannel;
import net.dv8tion.jda.api.events.interaction.ButtonClickEvent;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import zyenyo.Zyenyo;
Expand Down Expand Up @@ -117,5 +120,27 @@ else if (Aliases.DAILY.contains(args[0].toLowerCase()))
{
Zyenyo.masterThreadPool.submit(new Daily(event, args));
}

else if (Aliases.ACHIEVEMENTLIST.contains(args[0].toLowerCase()))
{
Zyenyo.masterThreadPool.submit(new AchievementList(event, args));
}

else if (Aliases.ACHIEVEMENT.contains(args[0].toLowerCase()))
{
Zyenyo.masterThreadPool.submit(new Achievement(event, args));
}
}

@Override
public void onButtonClick(ButtonClickEvent event) {
switch (event.getComponentId()) {
case "achievementListNext":
AchievementList.onNextPage(event);
break;
case "achievementListPrev":
AchievementList.onPrevPage(event);
break;
}
}
}
5 changes: 4 additions & 1 deletion src/main/java/commands/info/Help.java
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ public void onMessageReceived(MessageReceivedEvent event)
case "daily":
embed = InfoCard.DAILY;
break;
case "achievements": case "achievementlist": case "al":
embed = InfoCard.ACHIEVEMENTS;
break;
}
}
else {embed = InfoCard.FULL_HELP;}
Expand All @@ -84,4 +87,4 @@ public void onMessageReceived(MessageReceivedEvent event)
catch (IllegalStateException e) {channel.sendMessageEmbeds(InfoCard.commandNotFound(args[1]).build()).queue();}
}
}
}
}
9 changes: 9 additions & 0 deletions src/main/java/dataStructures/AchievementDetails.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package dataStructures;

/**
* Data about a specific achievement.
* @param title : name of achievement
* @param description : Description of the achievment
* @param thumbnail : the achievement icon, that will be displayed in the embed.
*/
public record AchievementDetails(String title, String description, String thumbnail ) {}
4 changes: 3 additions & 1 deletion src/main/java/dataStructures/AddTestResult.java
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
package dataStructures;

public record AddTestResult(double rawTp, Integer dailyStreak ) {}
import java.util.List;

public record AddTestResult(double rawTp, Integer dailyStreak, List<AchievementDetails> achievements ) {}
6 changes: 6 additions & 0 deletions src/main/java/dataStructures/Aliases.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ public final class Aliases
BotConfig.PREFIX + "lboard",
BotConfig.PREFIX + "lb");
public static final Set<String> DAILY = Collections.singleton(BotConfig.PREFIX + "daily");
public static final Set<String> ACHIEVEMENT = Collections.singleton(BotConfig.PREFIX + "achievement");

public final static Set<String> ACHIEVEMENTLIST = Set.of(
BotConfig.PREFIX + "achievementlist",
BotConfig.PREFIX + "achievements",
BotConfig.PREFIX + "al");


/*————————————————————————————————————|
Expand Down
11 changes: 10 additions & 1 deletion src/main/java/dataStructures/InfoCard.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public class InfoCard
// .addField("Chart", "Shows a chart of a user's typing stats.", false)
.addField("Leaderboard", "Shows the typing stats leaderboard of a specified statistic.", false)
.addField("Daily", "Shows daily streak information.", false)
.addField("Achievements", "Shows a list of all achievements.", false)
// .addField("DpiConverter", "Converts fullscreen DPI on one screen to another (not implemented).", false)
.setColor(0x8D538D);

Expand Down Expand Up @@ -196,6 +197,14 @@ public static EmbedBuilder commandNotFound(String command)
.addField("Aliases","`None`", false)
.addField("Syntax", "`\\daily`", false);

public static final EmbedBuilder ACHIEVEMENTS =
new EmbedBuilder()
.setTitle("CMD: Achievements.")
.setDescription("Displays a list of all available achievements.")
.setColor(0x8D538D)
.addField("Aliases","`achievementlist`, `al`", false)
.addField("Syntax", "`\\achievements`", false)
.addField("Hint", "View a specific achievement in detail with `\\achievement <achievement title>`", false);


/*—————————————————————————————————————|
Expand All @@ -210,4 +219,4 @@ public static EmbedBuilder commandNotFound(String command)
.addField("Aliases", "`dpiconv, dpicalculator, dpicalc`", false)
.addField("Syntax", "\\dpiconverter", false)
.setColor(0x8D538D);
}
}
10 changes: 5 additions & 5 deletions src/main/java/zyenyo/BotConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ public class BotConfig

public static int NUM_PROMPTS; // Set in CalculatePromptDifficulty.downloadAndUpdatePrompts.run();
public static final String BOT_DATA_FILEPATH = "ZBotData/";
public static final String SCRAPE_DATA_FILEPATH = "ZBotData/ScrapeData/";
public static final String INDEX_COUNTS_FILEPATH = "ZBotData/ScrapeData/COUNTS.zbif"; //ZBIF = ZyenyoBotIndexFile.
public static final String INDEX_IDS_FILEPATH = "ZBotData/ScrapeData/IDs.zbif";
public static final String SCRAPE_DATA_FILEPATH = "ZBotData/cache/user/ScrapeData/";
public static final String INDEX_COUNTS_FILEPATH = "ZBotData/cache/user/ScrapeData/COUNTS.zbif"; //ZBIF = ZyenyoBotIndexFile.
public static final String INDEX_IDS_FILEPATH = "ZBotData/cache/user/ScrapeData/IDs.zbif";
public static final List<Long> ADMINISTRATOR_IDS = List.of(642193466876493829l, 365691073156087819l);

protected static final File PROMPT_RATING_FILE = new File("ZBotData/TypingPrompts/PromptRatingMap.zbo");
protected static final File PROMPT_DIFFICULTY_FILE = new File("ZBotData/TypingPrompts/SortedPromptsList.zbo");
protected static final File PROMPT_RATING_FILE = new File("ZBotData/cache/TypingPrompts/PromptRatingMap.zbo");
protected static final File PROMPT_DIFFICULTY_FILE = new File("ZBotData/cache/TypingPrompts/SortedPromptsList.zbo");

protected static void setConfigVars(String ENVIRONMENT)
{
Expand Down
Loading

0 comments on commit a2e93d5

Please sign in to comment.