Add help command and command categories

This commit is contained in:
Bea 2022-12-20 17:05:59 +01:00
parent f9fe12a248
commit 480b8b5eda
16 changed files with 333 additions and 147 deletions

View File

@ -136,6 +136,7 @@ public class HidekoBot
messageCommandListener.registerCommand(new wtf.beatrice.hidekobot.commands.message.CoinFlipCommand());
messageCommandListener.registerCommand(new wtf.beatrice.hidekobot.commands.message.ClearCommand());
messageCommandListener.registerCommand(new wtf.beatrice.hidekobot.commands.message.DiceRollCommand());
messageCommandListener.registerCommand(new wtf.beatrice.hidekobot.commands.message.HelpCommand());
messageCommandListener.registerCommand(new wtf.beatrice.hidekobot.commands.message.InviteCommand());
messageCommandListener.registerCommand(new wtf.beatrice.hidekobot.commands.message.LoveCalculatorCommand());
messageCommandListener.registerCommand(new wtf.beatrice.hidekobot.commands.message.MagicBallCommand());

View File

@ -9,6 +9,7 @@ import org.jetbrains.annotations.Nullable;
import wtf.beatrice.hidekobot.Cache;
import wtf.beatrice.hidekobot.HidekoBot;
import wtf.beatrice.hidekobot.commands.base.Avatar;
import wtf.beatrice.hidekobot.objects.commands.CommandCategory;
import wtf.beatrice.hidekobot.objects.commands.MessageCommand;
import java.util.Collections;
@ -34,6 +35,11 @@ public class AvatarCommand implements MessageCommand
return false;
}
@Override
public CommandCategory getCategory() {
return CommandCategory.TOOLS;
}
@Override
public void runCommand(MessageReceivedEvent event, String label, String[] args)
{

View File

@ -6,6 +6,7 @@ import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.jetbrains.annotations.Nullable;
import wtf.beatrice.hidekobot.Cache;
import wtf.beatrice.hidekobot.commands.base.BotInfo;
import wtf.beatrice.hidekobot.objects.commands.CommandCategory;
import wtf.beatrice.hidekobot.objects.commands.MessageCommand;
import java.util.Collections;
@ -31,6 +32,11 @@ public class BotInfoCommand implements MessageCommand
return false;
}
@Override
public CommandCategory getCategory() {
return CommandCategory.TOOLS;
}
@Override
public void runCommand(MessageReceivedEvent event, String label, String[] args) {

View File

@ -6,6 +6,7 @@ import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.interactions.components.buttons.Button;
import wtf.beatrice.hidekobot.Cache;
import wtf.beatrice.hidekobot.commands.base.ClearChat;
import wtf.beatrice.hidekobot.objects.commands.CommandCategory;
import wtf.beatrice.hidekobot.objects.commands.MessageCommand;
import java.util.Collections;
@ -27,6 +28,10 @@ public class ClearCommand implements MessageCommand
public boolean passRawArgs() {
return false;
}
@Override
public CommandCategory getCategory() {
return CommandCategory.MODERATION;
}
@Override
public void runCommand(MessageReceivedEvent event, String label, String[] args)

View File

@ -4,6 +4,7 @@ import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.jetbrains.annotations.Nullable;
import wtf.beatrice.hidekobot.commands.base.CoinFlip;
import wtf.beatrice.hidekobot.objects.commands.CommandCategory;
import wtf.beatrice.hidekobot.objects.commands.MessageCommand;
import java.util.Arrays;
@ -29,6 +30,11 @@ public class CoinFlipCommand implements MessageCommand
return false;
}
@Override
public CommandCategory getCategory() {
return CommandCategory.FUN;
}
@Override
public void runCommand(MessageReceivedEvent event, String label, String[] args) {

View File

@ -6,165 +6,171 @@ import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.jetbrains.annotations.Nullable;
import wtf.beatrice.hidekobot.Cache;
import wtf.beatrice.hidekobot.objects.Dice;
import wtf.beatrice.hidekobot.objects.commands.CommandCategory;
import wtf.beatrice.hidekobot.objects.commands.MessageCommand;
import java.util.*;
public class DiceRollCommand implements MessageCommand
{
@Override
public LinkedList<String> getCommandLabels() {
return new LinkedList<>(Arrays.asList("diceroll", "droll", "roll"));
}
@Override
public LinkedList<String> getCommandLabels() {
return new LinkedList<>(Arrays.asList("diceroll", "droll", "roll"));
}
@Nullable
@Override
public List<Permission> getPermissions() {
return null; // anyone can use it
}
@Nullable
@Override
public List<Permission> getPermissions() {
return null; // anyone can use it
}
@Override
public boolean passRawArgs() {
return false;
}
@Override
public boolean passRawArgs() {
return false;
}
@Override
public void runCommand(MessageReceivedEvent event, String label, String[] args)
@Override
public CommandCategory getCategory() {
return CommandCategory.FUN;
}
@Override
public void runCommand(MessageReceivedEvent event, String label, String[] args)
{
LinkedHashMap<Dice, Integer> dicesToRoll = new LinkedHashMap<>();
String diceRegex = "d[0-9]+";
String amountRegex = "[0-9]+";
Dice currentDice = null;
int currentAmount;
UUID lastPushedDice = null;
int totalRolls = 0;
for(String arg : args)
{
LinkedHashMap<Dice, Integer> dicesToRoll = new LinkedHashMap<>();
String diceRegex = "d[0-9]+";
String amountRegex = "[0-9]+";
Dice currentDice = null;
int currentAmount;
UUID lastPushedDice = null;
int totalRolls = 0;
for(String arg : args)
if(totalRolls > 200)
{
if(totalRolls > 200)
{
event.getMessage().reply("Too many total rolls!").queue();
return;
}
if(arg.matches(amountRegex))
{
currentAmount = Integer.parseInt(arg);
if(currentDice == null)
{
currentDice = new Dice(6);
} else {
currentDice = new Dice(currentDice);
}
if(currentAmount > 100)
{
event.getMessage().reply("Too many rolls (`" + currentAmount + "`)!").queue();
return;
}
lastPushedDice = currentDice.getUUID();
dicesToRoll.put(currentDice, currentAmount);
totalRolls += currentAmount;
}
else if(arg.matches(diceRegex))
{
int sides = Integer.parseInt(arg.substring(1));
if(sides > 10000)
{
event.getMessage().reply("Too many sides (`" + sides + "`)!").queue();
return;
}
if(args.length == 1)
{
dicesToRoll.put(new Dice(sides), 1);
totalRolls++;
} else
{
if(currentDice != null)
{
if(lastPushedDice == null || !lastPushedDice.equals(currentDice.getUUID()))
{
dicesToRoll.put(currentDice, 1);
lastPushedDice = currentDice.getUUID();
totalRolls++;
}
}
currentDice = new Dice(sides);
}
}
}
if(lastPushedDice == null)
{
if(currentDice != null)
{
dicesToRoll.put(currentDice, 1);
totalRolls++;
}
} else
{
if(!lastPushedDice.equals(currentDice.getUUID()))
{
dicesToRoll.put(new Dice(currentDice), 1);
totalRolls++;
}
}
LinkedList<Dice> rolledDices = new LinkedList<>();
for(Dice dice : dicesToRoll.keySet())
{
for(int roll = 0; roll < dicesToRoll.get(dice); roll++)
{
dice.roll();
rolledDices.add(new Dice(dice));
}
}
EmbedBuilder embedBuilder = new EmbedBuilder();
embedBuilder.setColor(Cache.getBotColor());
embedBuilder.setAuthor(event.getAuthor().getAsTag(), null, event.getAuthor().getAvatarUrl());
embedBuilder.setTitle("Dice Roll");
StringBuilder message = new StringBuilder();
int total = 0;
int previousDiceSides = 0;
for (Dice dice : rolledDices) {
int diceSize = dice.getSides();
if (previousDiceSides != diceSize) {
message.append("\nd").append(diceSize).append(": ");
previousDiceSides = diceSize;
} else if (previousDiceSides != 0) {
message.append(", ");
}
message.append("`").append(dice.getValue()).append("`");
total += dice.getValue();
}
// discord doesn't allow embed fields to be longer than 1024 and errors out
if(message.length() > 1024)
{
event.getMessage().reply("Too many rolls!").queue();
event.getMessage().reply("Too many total rolls!").queue();
return;
}
embedBuilder.addField("\uD83C\uDFB2 Rolls", message.toString(), false);
if(arg.matches(amountRegex))
{
currentAmount = Integer.parseInt(arg);
embedBuilder.addField("✨ Total", totalRolls + " rolls: " + total, false);
if(currentDice == null)
{
currentDice = new Dice(6);
} else {
currentDice = new Dice(currentDice);
}
if(currentAmount > 100)
{
event.getMessage().reply("Too many rolls (`" + currentAmount + "`)!").queue();
return;
}
event.getMessage().replyEmbeds(embedBuilder.build()).queue();
lastPushedDice = currentDice.getUUID();
dicesToRoll.put(currentDice, currentAmount);
totalRolls += currentAmount;
}
else if(arg.matches(diceRegex))
{
int sides = Integer.parseInt(arg.substring(1));
if(sides > 10000)
{
event.getMessage().reply("Too many sides (`" + sides + "`)!").queue();
return;
}
if(args.length == 1)
{
dicesToRoll.put(new Dice(sides), 1);
totalRolls++;
} else
{
if(currentDice != null)
{
if(lastPushedDice == null || !lastPushedDice.equals(currentDice.getUUID()))
{
dicesToRoll.put(currentDice, 1);
lastPushedDice = currentDice.getUUID();
totalRolls++;
}
}
currentDice = new Dice(sides);
}
}
}
if(lastPushedDice == null)
{
if(currentDice != null)
{
dicesToRoll.put(currentDice, 1);
totalRolls++;
}
} else
{
if(!lastPushedDice.equals(currentDice.getUUID()))
{
dicesToRoll.put(new Dice(currentDice), 1);
totalRolls++;
}
}
LinkedList<Dice> rolledDices = new LinkedList<>();
for(Dice dice : dicesToRoll.keySet())
{
for(int roll = 0; roll < dicesToRoll.get(dice); roll++)
{
dice.roll();
rolledDices.add(new Dice(dice));
}
}
EmbedBuilder embedBuilder = new EmbedBuilder();
embedBuilder.setColor(Cache.getBotColor());
embedBuilder.setAuthor(event.getAuthor().getAsTag(), null, event.getAuthor().getAvatarUrl());
embedBuilder.setTitle("Dice Roll");
StringBuilder message = new StringBuilder();
int total = 0;
int previousDiceSides = 0;
for (Dice dice : rolledDices) {
int diceSize = dice.getSides();
if (previousDiceSides != diceSize) {
message.append("\nd").append(diceSize).append(": ");
previousDiceSides = diceSize;
} else if (previousDiceSides != 0) {
message.append(", ");
}
message.append("`").append(dice.getValue()).append("`");
total += dice.getValue();
}
// discord doesn't allow embed fields to be longer than 1024 and errors out
if(message.length() > 1024)
{
event.getMessage().reply("Too many rolls!").queue();
return;
}
embedBuilder.addField("\uD83C\uDFB2 Rolls", message.toString(), false);
embedBuilder.addField("✨ Total", totalRolls + " rolls: " + total, false);
event.getMessage().replyEmbeds(embedBuilder.build()).queue();
}
}

View File

@ -2,6 +2,7 @@ package wtf.beatrice.hidekobot.commands.message;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import wtf.beatrice.hidekobot.objects.commands.CommandCategory;
import wtf.beatrice.hidekobot.objects.commands.MessageCommand;
import java.util.Arrays;
@ -24,6 +25,11 @@ public class HelloCommand implements MessageCommand
return false;
}
@Override
public CommandCategory getCategory() {
return CommandCategory.FUN;
}
@Override
public void runCommand(MessageReceivedEvent event, String label, String[] args)
{

View File

@ -0,0 +1,95 @@
package wtf.beatrice.hidekobot.commands.message;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.apache.commons.text.WordUtils;
import org.jetbrains.annotations.Nullable;
import wtf.beatrice.hidekobot.Cache;
import wtf.beatrice.hidekobot.commands.base.Say;
import wtf.beatrice.hidekobot.objects.commands.CommandCategory;
import wtf.beatrice.hidekobot.objects.commands.MessageCommand;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
public class HelpCommand implements MessageCommand
{
@Override
public LinkedList<String> getCommandLabels() {
return new LinkedList<>(Collections.singletonList("help"));
}
@Nullable
@Override
public List<Permission> getPermissions() { return null; }
@Override
public boolean passRawArgs() {
return false;
}
@Override
public CommandCategory getCategory() {
return CommandCategory.TOOLS;
}
@Override
public void runCommand(MessageReceivedEvent event, String label, String[] args)
{
LinkedHashMap<CommandCategory, LinkedList<MessageCommand>> commandCategories = new LinkedHashMap<>();
if(args.length == 0)
{
for(CommandCategory category : CommandCategory.values())
{
LinkedList<MessageCommand> commandsOfThisCategory = new LinkedList<>();
for (MessageCommand command : Cache.getMessageCommandListener().getRegisteredCommands())
{
if(command.getCategory().equals(category))
{
commandsOfThisCategory.add(command);
}
}
commandCategories.put(category, commandsOfThisCategory);
}
EmbedBuilder embedBuilder = new EmbedBuilder();
embedBuilder.setColor(Cache.getBotColor());
embedBuilder.setTitle("Bot Help");
embedBuilder.addField("General Help",
"Type `" + Cache.getBotPrefix() + " help [command]` to get help on a specific command." +
"\nYou will find a list of commands organized in categories below.",
false);
for(CommandCategory category : commandCategories.keySet())
{
StringBuilder commandsList = new StringBuilder();
LinkedList<MessageCommand> commandsOfThisCategory = commandCategories.get(category);
for(int pos = 0; pos < commandsOfThisCategory.size(); pos++)
{
MessageCommand command = commandsOfThisCategory.get(pos);
commandsList.append("`").append(command.getCommandLabels().get(0)).append("`");
if(pos + 1 != commandsOfThisCategory.size())
commandsList.append(", "); // separate with comma except on last run
}
String niceCategoryName = category.name().replace("_", " ");
niceCategoryName = WordUtils.capitalizeFully(niceCategoryName);
niceCategoryName = category.getEmoji() + " " + niceCategoryName;
embedBuilder.addField(niceCategoryName, commandsList.toString(), false);
}
event.getMessage().replyEmbeds(embedBuilder.build()).queue();
}
}
}

View File

@ -7,6 +7,7 @@ import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.interactions.components.buttons.Button;
import org.jetbrains.annotations.Nullable;
import wtf.beatrice.hidekobot.commands.base.Invite;
import wtf.beatrice.hidekobot.objects.commands.CommandCategory;
import wtf.beatrice.hidekobot.objects.commands.MessageCommand;
import java.util.Collections;
@ -32,6 +33,11 @@ public class InviteCommand implements MessageCommand
return false;
}
@Override
public CommandCategory getCategory() {
return CommandCategory.FUN;
}
@Override
public void runCommand(MessageReceivedEvent event, String label, String[] args)
{

View File

@ -9,6 +9,7 @@ import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.jetbrains.annotations.Nullable;
import wtf.beatrice.hidekobot.Cache;
import wtf.beatrice.hidekobot.HidekoBot;
import wtf.beatrice.hidekobot.objects.commands.CommandCategory;
import wtf.beatrice.hidekobot.objects.commands.MessageCommand;
import wtf.beatrice.hidekobot.util.RandomUtil;
@ -37,6 +38,11 @@ public class LoveCalculatorCommand implements MessageCommand
return false;
}
@Override
public CommandCategory getCategory() {
return CommandCategory.FUN;
}
@Override
public void runCommand(MessageReceivedEvent event, String label, String[] args)
{

View File

@ -4,6 +4,7 @@ import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.jetbrains.annotations.Nullable;
import wtf.beatrice.hidekobot.commands.base.MagicBall;
import wtf.beatrice.hidekobot.objects.commands.CommandCategory;
import wtf.beatrice.hidekobot.objects.commands.MessageCommand;
import java.util.LinkedList;
@ -28,6 +29,11 @@ public class MagicBallCommand implements MessageCommand
return false;
}
@Override
public CommandCategory getCategory() {
return CommandCategory.FUN;
}
@Override
public void runCommand(MessageReceivedEvent event, String label, String[] args)
{

View File

@ -4,6 +4,7 @@ import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.jetbrains.annotations.Nullable;
import wtf.beatrice.hidekobot.commands.base.Say;
import wtf.beatrice.hidekobot.objects.commands.CommandCategory;
import wtf.beatrice.hidekobot.objects.commands.MessageCommand;
import java.util.Collections;
@ -28,6 +29,11 @@ public class SayCommand implements MessageCommand
return true;
}
@Override
public CommandCategory getCategory() {
return CommandCategory.TOOLS;
}
@Override
public void runCommand(MessageReceivedEvent event, String label, String[] args)
{

View File

@ -9,6 +9,7 @@ import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
import wtf.beatrice.hidekobot.commands.base.UrbanDictionary;
import wtf.beatrice.hidekobot.objects.commands.CommandCategory;
import wtf.beatrice.hidekobot.objects.commands.MessageCommand;
import java.io.IOException;
@ -34,7 +35,10 @@ public class UrbanDictionaryCommand implements MessageCommand
return false;
}
@Override
public CommandCategory getCategory() {
return CommandCategory.FUN;
}
@Override

View File

@ -7,14 +7,12 @@ import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.jetbrains.annotations.NotNull;
import wtf.beatrice.hidekobot.objects.commands.CommandCategory;
import wtf.beatrice.hidekobot.objects.commands.MessageCommand;
import wtf.beatrice.hidekobot.objects.comparators.MessageCommandAliasesComparator;
import wtf.beatrice.hidekobot.util.Logger;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.TreeMap;
import java.util.*;
public class MessageCommandListener extends ListenerAdapter
{
@ -23,6 +21,10 @@ public class MessageCommandListener extends ListenerAdapter
private final TreeMap<LinkedList<String>, MessageCommand> registeredCommands =
new TreeMap<LinkedList<String>, MessageCommand>(new MessageCommandAliasesComparator());
// map commands and their categories.
// this is not strictly needed but it's better to have it so we avoid looping every time we need to check the cat.
LinkedHashMap<CommandCategory, LinkedList<MessageCommand>> commandCategories = new LinkedHashMap<>();
private final String commandRegex = "(?i)^(hideko|hde)\\b";
// (?i) -> case insensitive flag
// ^ -> start of string (not in middle of a sentence)

View File

@ -0,0 +1,18 @@
package wtf.beatrice.hidekobot.objects.commands;
public enum CommandCategory
{
MODERATION("\uD83D\uDC40"),
FUN("\uD83C\uDFB2"),
TOOLS("\uD83D\uDEE0"),
;
private String emoji;
CommandCategory(String emoji)
{
this.emoji = emoji;
}
public String getEmoji() { return emoji; }
}

View File

@ -39,6 +39,13 @@ public interface MessageCommand
*/
boolean passRawArgs();
/**
* Say what category this command belongs to.
*
* @return the command category.
*/
CommandCategory getCategory();
/**
* Run the command logic by parsing the event and replying accordingly.
*