From 4e866895a045379d03f50fe43f7eb88c865e8114 Mon Sep 17 00:00:00 2001 From: Liam Date: Fri, 5 Jul 2024 19:07:32 +0100 Subject: [PATCH] impl counter feature --- .../cc/fascinated/bat/common/NumberUtils.java | 20 +++++ .../commands/server/MemberCountCommand.java | 23 +---- .../bat/features/counter/CounterChannel.java | 81 +++++++++++++++++ .../bat/features/counter/CounterFeature.java | 22 +++++ .../bat/features/counter/CounterProfile.java | 89 +++++++++++++++++++ .../bat/features/counter/CounterResult.java | 10 +++ .../features/counter/CountingListener.java | 53 +++++++++++ .../counter/command/CounterCommand.java | 26 ++++++ .../counter/command/RemoveSubCommand.java | 77 ++++++++++++++++ .../command/SetBreakingSubCommand.java | 80 +++++++++++++++++ .../counter/command/SetSubCommand.java | 80 +++++++++++++++++ .../counter/command/SetupSubCommand.java | 67 ++++++++++++++ .../cc/fascinated/bat/model/BatGuild.java | 10 +++ 13 files changed, 618 insertions(+), 20 deletions(-) create mode 100644 src/main/java/cc/fascinated/bat/common/NumberUtils.java create mode 100644 src/main/java/cc/fascinated/bat/features/counter/CounterChannel.java create mode 100644 src/main/java/cc/fascinated/bat/features/counter/CounterFeature.java create mode 100644 src/main/java/cc/fascinated/bat/features/counter/CounterProfile.java create mode 100644 src/main/java/cc/fascinated/bat/features/counter/CounterResult.java create mode 100644 src/main/java/cc/fascinated/bat/features/counter/CountingListener.java create mode 100644 src/main/java/cc/fascinated/bat/features/counter/command/CounterCommand.java create mode 100644 src/main/java/cc/fascinated/bat/features/counter/command/RemoveSubCommand.java create mode 100644 src/main/java/cc/fascinated/bat/features/counter/command/SetBreakingSubCommand.java create mode 100644 src/main/java/cc/fascinated/bat/features/counter/command/SetSubCommand.java create mode 100644 src/main/java/cc/fascinated/bat/features/counter/command/SetupSubCommand.java diff --git a/src/main/java/cc/fascinated/bat/common/NumberUtils.java b/src/main/java/cc/fascinated/bat/common/NumberUtils.java new file mode 100644 index 0000000..a574c8b --- /dev/null +++ b/src/main/java/cc/fascinated/bat/common/NumberUtils.java @@ -0,0 +1,20 @@ +package cc.fascinated.bat.common; + +/** + * @author Fascinated (fascinated7) + */ +public class NumberUtils { + /** + * Parses a string to an integer + * + * @param input the string to parse + * @return the parsed integer, or -1 if invalid + */ + public static int parseInt(String input) { + try { + return Integer.parseInt(input); + } catch (NumberFormatException exception) { + return -1; + } + } +} diff --git a/src/main/java/cc/fascinated/bat/features/base/commands/server/MemberCountCommand.java b/src/main/java/cc/fascinated/bat/features/base/commands/server/MemberCountCommand.java index 8bbc8fd..8aa358c 100644 --- a/src/main/java/cc/fascinated/bat/features/base/commands/server/MemberCountCommand.java +++ b/src/main/java/cc/fascinated/bat/features/base/commands/server/MemberCountCommand.java @@ -28,11 +28,7 @@ public class MemberCountCommand extends BatCommand { public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) { Guild discordGuild = guild.getDiscordGuild(); int totalMembers = 0, totalUsers = 0, totalBots = 0; - Map memberCounts = new HashMap<>(); for (Member guildMember : discordGuild.getMembers()) { - OnlineStatus status = guildMember.getOnlineStatus(); - memberCounts.put(status, memberCounts.getOrDefault(status, 0) + 1); - if (guildMember.getUser().isBot()) { totalBots++; } else { @@ -46,23 +42,10 @@ public class MemberCountCommand extends BatCommand { Total Members: `%s` Total Users: `%s` Total Bots: `%s` - \s - **Member Presence** - %s Online: `%s` - %s Idle: `%s` - %s Do Not Disturb: `%s` - %s Offline: `%s`""".formatted( + """.formatted( NumberFormatter.format(totalMembers), NumberFormatter.format(totalUsers), - NumberFormatter.format(totalBots), - Emojis.ONLINE_EMOJI, - NumberFormatter.format(memberCounts.getOrDefault(OnlineStatus.ONLINE, 0)), - Emojis.IDLE_EMOJI, - NumberFormatter.format(memberCounts.getOrDefault(OnlineStatus.IDLE, 0)), - Emojis.DND_EMOJI, - NumberFormatter.format(memberCounts.getOrDefault(OnlineStatus.DO_NOT_DISTURB, 0)), - Emojis.OFFLINE_EMOJI, - NumberFormatter.format(memberCounts.getOrDefault(OnlineStatus.OFFLINE, 0)))) - .build()).queue(); + NumberFormatter.format(totalBots) + )).build()).queue(); } } \ No newline at end of file diff --git a/src/main/java/cc/fascinated/bat/features/counter/CounterChannel.java b/src/main/java/cc/fascinated/bat/features/counter/CounterChannel.java new file mode 100644 index 0000000..62424ef --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/counter/CounterChannel.java @@ -0,0 +1,81 @@ +package cc.fascinated.bat.features.counter; + +import cc.fascinated.bat.common.ChannelUtils; +import cc.fascinated.bat.common.NumberUtils; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; + +/** + * @author Fascinated (fascinated7) + */ +@AllArgsConstructor +@Getter +@Setter +public class CounterChannel { + /** + * The channel id of this counter channel + */ + private final String channelId; + + /** + * The current count of this counter channel + */ + private int currentCount; + + /** + * Whether the counter should reset when a user + * inputs the wrong number or a non number + */ + private boolean breakable; + + /** + * Increment the counter + * + * @param input the input to increment the counter with + * @return the return type of the increment + */ + public CounterResult incrementChannel(String input) { + int number = NumberUtils.parseInt(input); + + // The number is invalid + if (number == -1 || number != this.nextNumber()) { + // The counter was broken + if (this.isBreakable()) { + this.reset(); + return CounterResult.BROKEN; + } + return CounterResult.INVALID_NUMBER; + } + + this.currentCount++; + return CounterResult.SUCCESS; + } + + /** + * Gets the next number for this counter + */ + public int nextNumber() { + return currentCount + 1; + } + + /** + * Resets the current count + *

+ * This usually happens if the counter is broken + *

+ */ + public void reset() { + currentCount = 0; + } + + /** + * Gets the channel + * + * @return the channel + */ + public TextChannel getChannel() { + return ChannelUtils.getTextChannel(channelId); + } +} diff --git a/src/main/java/cc/fascinated/bat/features/counter/CounterFeature.java b/src/main/java/cc/fascinated/bat/features/counter/CounterFeature.java new file mode 100644 index 0000000..8610047 --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/counter/CounterFeature.java @@ -0,0 +1,22 @@ +package cc.fascinated.bat.features.counter; + +import cc.fascinated.bat.features.Feature; +import cc.fascinated.bat.features.counter.command.CounterCommand; +import cc.fascinated.bat.service.CommandService; +import lombok.NonNull; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +/** + * @author Fascinated (fascinated7) + */ +@Component +public class CounterFeature extends Feature { + @Autowired + public CounterFeature(@NonNull ApplicationContext context, @NonNull CommandService commandService) { + super("Counter", true); + + super.registerCommand(commandService, context.getBean(CounterCommand.class)); + } +} diff --git a/src/main/java/cc/fascinated/bat/features/counter/CounterProfile.java b/src/main/java/cc/fascinated/bat/features/counter/CounterProfile.java new file mode 100644 index 0000000..b1fd26c --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/counter/CounterProfile.java @@ -0,0 +1,89 @@ +package cc.fascinated.bat.features.counter; + +import cc.fascinated.bat.common.Serializable; +import com.google.gson.Gson; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import org.bson.Document; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Fascinated (fascinated7) + */ +@Component +public class CounterProfile extends Serializable { + /** + * The counter channels in this guild + */ + private final List counters = new ArrayList<>(); + + /** + * Gets the counter channel by the channel id + * + * @param channelId the id of the channel + * @return the counter channel + */ + public CounterChannel getCounterChannel(String channelId) { + for (CounterChannel counter : counters) { + if (counter.getChannelId().equals(channelId)) { + return counter; + } + } + return null; + } + + /** + * Removes the channel from the counter channels + * + * @param channel the channel to remove + */ + public void removeChannel(TextChannel channel) { + CounterChannel counterChannel = getCounterChannel(channel.getId()); + if (counterChannel != null) { + counters.remove(counterChannel); + } + } + + /** + * Sets up the channel as a counter channel + * + * @param channel the channel to set as a counter channel + * @param breakable whether the counter should reset when a user inputs the wrong number or a non number + */ + public void setupChannel(TextChannel channel, boolean breakable) { + counters.add(new CounterChannel(channel.getId(), 0, breakable)); + } + + @Override + public void load(Document document, Gson gson) { + for (Document counterDocument : document.getList("counters", Document.class, new ArrayList<>())) { + counters.add(new CounterChannel( + counterDocument.getString("channelId"), + counterDocument.getInteger("currentCount"), + counterDocument.getBoolean("breakable") + )); + } + } + + @Override + public Document serialize(Gson gson) { + Document document = new Document(); + List counterDocuments = new ArrayList<>(); + for (CounterChannel counter : counters) { + Document counterDocument = new Document(); + counterDocument.append("channelId", counter.getChannelId()); + counterDocument.append("currentCount", counter.getCurrentCount()); + counterDocument.append("breakable", counter.isBreakable()); + counterDocuments.add(counterDocument); + } + document.append("counters", counterDocuments); + return document; + } + + @Override + public void reset() { + counters.clear(); + } +} diff --git a/src/main/java/cc/fascinated/bat/features/counter/CounterResult.java b/src/main/java/cc/fascinated/bat/features/counter/CounterResult.java new file mode 100644 index 0000000..a857a22 --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/counter/CounterResult.java @@ -0,0 +1,10 @@ +package cc.fascinated.bat.features.counter; + +/** + * @author Fascinated (fascinated7) + */ +public enum CounterResult { + SUCCESS, + BROKEN, + INVALID_NUMBER, +} diff --git a/src/main/java/cc/fascinated/bat/features/counter/CountingListener.java b/src/main/java/cc/fascinated/bat/features/counter/CountingListener.java new file mode 100644 index 0000000..97bc426 --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/counter/CountingListener.java @@ -0,0 +1,53 @@ +package cc.fascinated.bat.features.counter; + +import cc.fascinated.bat.event.EventListener; +import cc.fascinated.bat.features.base.profile.FeatureProfile; +import cc.fascinated.bat.model.BatGuild; +import cc.fascinated.bat.model.BatUser; +import lombok.NonNull; +import net.dv8tion.jda.api.entities.emoji.Emoji; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * @author Fascinated (fascinated7) + */ +@Component +public class CountingListener implements EventListener { + private final CounterFeature counterFeature; + + @Autowired + public CountingListener(@NonNull CounterFeature counterFeature) { + this.counterFeature = counterFeature; + } + + @Override + public void onGuildMessageReceive(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull MessageReceivedEvent event) { + FeatureProfile featureProfile = guild.getFeatureProfile(); + if (featureProfile.isFeatureDisabled(counterFeature)) { + return; + } + CounterProfile counterProfile = guild.getCounterProfile(); + if (counterProfile == null) { + return; + } + CounterChannel counterChannel = counterProfile.getCounterChannel(event.getChannel().getId()); + if (counterChannel == null) { + return; + } + CounterResult result = counterChannel.incrementChannel(event.getMessage().getContentRaw()); + if (result == null) { + return; + } + + switch (result) { + case SUCCESS -> event.getMessage().addReaction(Emoji.fromUnicode("✅")).queue(); + case INVALID_NUMBER -> event.getMessage().addReaction(Emoji.fromUnicode("❌")).queue(); + case BROKEN -> { + event.getMessage().addReaction(Emoji.fromUnicode("❌")).queue(); + event.getMessage().reply("%s, you have broken the counter!".formatted(event.getAuthor().getAsMention())).queue(); + } + } + } +} diff --git a/src/main/java/cc/fascinated/bat/features/counter/command/CounterCommand.java b/src/main/java/cc/fascinated/bat/features/counter/command/CounterCommand.java new file mode 100644 index 0000000..a19022d --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/counter/command/CounterCommand.java @@ -0,0 +1,26 @@ +package cc.fascinated.bat.features.counter.command; + +import cc.fascinated.bat.command.BatCommand; +import cc.fascinated.bat.command.CommandInfo; +import lombok.NonNull; +import net.dv8tion.jda.api.Permission; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +/** + * @author Fascinated (fascinated7) + */ +@Component +@CommandInfo(name = "counter", description = "View or configure the counter settings", requiredPermissions = Permission.MANAGE_CHANNEL) +public class CounterCommand extends BatCommand { + @Autowired + public CounterCommand(@NonNull ApplicationContext context) { + super.addSubCommands( + context.getBean(SetupSubCommand.class), + context.getBean(SetSubCommand.class), + context.getBean(RemoveSubCommand.class), + context.getBean(SetBreakingSubCommand.class) + ); + } +} diff --git a/src/main/java/cc/fascinated/bat/features/counter/command/RemoveSubCommand.java b/src/main/java/cc/fascinated/bat/features/counter/command/RemoveSubCommand.java new file mode 100644 index 0000000..37cbdbe --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/counter/command/RemoveSubCommand.java @@ -0,0 +1,77 @@ +package cc.fascinated.bat.features.counter.command; + +import cc.fascinated.bat.Emojis; +import cc.fascinated.bat.command.BatCommand; +import cc.fascinated.bat.command.CommandInfo; +import cc.fascinated.bat.common.EmbedUtils; +import cc.fascinated.bat.common.NumberFormatter; +import cc.fascinated.bat.features.counter.CounterChannel; +import cc.fascinated.bat.features.counter.CounterProfile; +import cc.fascinated.bat.model.BatGuild; +import cc.fascinated.bat.model.BatUser; +import lombok.NonNull; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.channel.ChannelType; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; +import net.dv8tion.jda.api.entities.channel.unions.GuildChannelUnion; +import net.dv8tion.jda.api.interactions.commands.OptionMapping; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction; +import net.dv8tion.jda.api.interactions.commands.build.OptionData; +import org.springframework.stereotype.Component; + +/** + * @author Fascinated (fascinated7) + */ +@Component("counter.remove:sub") +@CommandInfo(name = "remove", description = "Remove a counter channel") +public class RemoveSubCommand extends BatCommand { + public RemoveSubCommand() { + super.addOptions(new OptionData(OptionType.CHANNEL, "channel", "The channel to set the count in", true)); + } + + @Override + public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) { + OptionMapping channelOption = event.getOption("channel"); + if (channelOption == null) { + return; + } + GuildChannelUnion targetChannel = channelOption.getAsChannel(); + if (targetChannel.getType() != ChannelType.TEXT) { + event.replyEmbeds(EmbedUtils.errorEmbed() + .setDescription("%s The channel must be a text channel".formatted(Emojis.CROSS_MARK_EMOJI)) + .build()).queue(); + return; + } + TextChannel textChannel = targetChannel.asTextChannel(); + CounterProfile profile = guild.getCounterProfile(); + if (profile == null) { + return; + } + + // Check if the channel is a counter channel + CounterChannel counterChannel = profile.getCounterChannel(textChannel.getId()); + if (counterChannel == null) { + event.replyEmbeds(EmbedUtils.errorEmbed() + .setDescription("%s The channel %s is not a counter channel".formatted( + Emojis.CROSS_MARK_EMOJI, + textChannel.getAsMention() + )) + .build()).queue(); + return; + } + + profile.removeChannel(textChannel); + event.replyEmbeds(EmbedUtils.successEmbed() + .setDescription(""" + %s Successfully removed the counter channel %s + The count was `%s` + """.formatted( + Emojis.CHECK_MARK_EMOJI, + textChannel.getAsMention(), + NumberFormatter.formatCommas(counterChannel.getCurrentCount()) + )) + .build()).queue(); + } +} diff --git a/src/main/java/cc/fascinated/bat/features/counter/command/SetBreakingSubCommand.java b/src/main/java/cc/fascinated/bat/features/counter/command/SetBreakingSubCommand.java new file mode 100644 index 0000000..2ea84df --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/counter/command/SetBreakingSubCommand.java @@ -0,0 +1,80 @@ +package cc.fascinated.bat.features.counter.command; + +import cc.fascinated.bat.Emojis; +import cc.fascinated.bat.command.BatCommand; +import cc.fascinated.bat.command.CommandInfo; +import cc.fascinated.bat.common.EmbedUtils; +import cc.fascinated.bat.features.counter.CounterChannel; +import cc.fascinated.bat.features.counter.CounterProfile; +import cc.fascinated.bat.model.BatGuild; +import cc.fascinated.bat.model.BatUser; +import lombok.NonNull; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.channel.ChannelType; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; +import net.dv8tion.jda.api.entities.channel.unions.GuildChannelUnion; +import net.dv8tion.jda.api.interactions.commands.OptionMapping; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction; +import net.dv8tion.jda.api.interactions.commands.build.OptionData; +import org.springframework.stereotype.Component; + +/** + * @author Fascinated (fascinated7) + */ +@Component("counter.setbreaking:sub") +@CommandInfo(name = "setbreaking", description = "Updates if the counter should break") +public class SetBreakingSubCommand extends BatCommand { + public SetBreakingSubCommand() { + super.addOptions(new OptionData(OptionType.CHANNEL, "channel", "The channel to set the count in", true)); + super.addOptions(new OptionData(OptionType.BOOLEAN, "breakable", "Should the channel break on a invalid or wrong number", true)); + } + + @Override + public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) { + OptionMapping channelOption = event.getOption("channel"); + OptionMapping breakableOption = event.getOption("breakable"); + if (channelOption == null || breakableOption == null) { + return; + } + GuildChannelUnion targetChannel = channelOption.getAsChannel(); + if (targetChannel.getType() != ChannelType.TEXT) { + event.replyEmbeds(EmbedUtils.errorEmbed() + .setDescription("%s The channel must be a text channel".formatted(Emojis.CROSS_MARK_EMOJI)) + .build()).queue(); + return; + } + TextChannel textChannel = targetChannel.asTextChannel(); + boolean breakable = breakableOption.getAsBoolean(); + + CounterProfile profile = guild.getCounterProfile(); + if (profile == null) { + return; + } + + // Check if the channel is a counter channel + CounterChannel counterChannel = profile.getCounterChannel(textChannel.getId()); + if (counterChannel == null) { + event.replyEmbeds(EmbedUtils.errorEmbed() + .setDescription("%s The channel %s is not a counter channel".formatted( + Emojis.CROSS_MARK_EMOJI, + textChannel.getAsMention() + )) + .build()).queue(); + return; + } + + counterChannel.setBreakable(breakable); + event.replyEmbeds(EmbedUtils.successEmbed() + .setDescription("%s The counter in %s will %s break on an invalid or wrong number".formatted( + Emojis.CHECK_MARK_EMOJI, + textChannel.getAsMention(), + breakable ? "now" : "no longer" + )) + .build()).queue(); + counterChannel.getChannel().sendMessage("The counter will %s break on an invalid or wrong number".formatted( + breakable ? "now" : "no longer" + )).queue(); + } +} diff --git a/src/main/java/cc/fascinated/bat/features/counter/command/SetSubCommand.java b/src/main/java/cc/fascinated/bat/features/counter/command/SetSubCommand.java new file mode 100644 index 0000000..3baed77 --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/counter/command/SetSubCommand.java @@ -0,0 +1,80 @@ +package cc.fascinated.bat.features.counter.command; + +import cc.fascinated.bat.Emojis; +import cc.fascinated.bat.command.BatCommand; +import cc.fascinated.bat.command.CommandInfo; +import cc.fascinated.bat.common.EmbedUtils; +import cc.fascinated.bat.features.counter.CounterChannel; +import cc.fascinated.bat.features.counter.CounterProfile; +import cc.fascinated.bat.model.BatGuild; +import cc.fascinated.bat.model.BatUser; +import lombok.NonNull; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.channel.ChannelType; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; +import net.dv8tion.jda.api.entities.channel.unions.GuildChannelUnion; +import net.dv8tion.jda.api.interactions.commands.OptionMapping; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction; +import net.dv8tion.jda.api.interactions.commands.build.OptionData; +import org.springframework.stereotype.Component; + +/** + * @author Fascinated (fascinated7) + */ +@Component("counter.set:sub") +@CommandInfo(name = "set", description = "Set the current count in a channel") +public class SetSubCommand extends BatCommand { + public SetSubCommand() { + super.addOptions(new OptionData(OptionType.CHANNEL, "channel", "The channel to set the count in", true)); + super.addOptions(new OptionData(OptionType.INTEGER, "count", "The count to set", true)); + } + + @Override + public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) { + OptionMapping channelOption = event.getOption("channel"); + OptionMapping countOption = event.getOption("count"); + if (channelOption == null || countOption == null) { + return; + } + GuildChannelUnion targetChannel = channelOption.getAsChannel(); + if (targetChannel.getType() != ChannelType.TEXT) { + event.replyEmbeds(EmbedUtils.errorEmbed() + .setDescription("%s The channel must be a text channel".formatted(Emojis.CROSS_MARK_EMOJI)) + .build()).queue(); + return; + } + TextChannel textChannel = targetChannel.asTextChannel(); + int count = countOption.getAsInt(); + + CounterProfile profile = guild.getCounterProfile(); + if (profile == null) { + return; + } + + // Check if the channel is a counter channel + CounterChannel counterChannel = profile.getCounterChannel(textChannel.getId()); + if (counterChannel == null) { + event.replyEmbeds(EmbedUtils.errorEmbed() + .setDescription("%s The channel %s is not a counter channel".formatted( + Emojis.CROSS_MARK_EMOJI, + textChannel.getAsMention() + )) + .build()).queue(); + return; + } + + counterChannel.setCurrentCount(count); + event.replyEmbeds(EmbedUtils.successEmbed() + .setDescription("%s Successfully set the count in %s to %d".formatted( + Emojis.CHECK_MARK_EMOJI, + textChannel.getAsMention(), + count + )) + .build()).queue(); + counterChannel.getChannel().sendMessage("The count has been set to `%s`".formatted( + count + )).queue(); + } +} diff --git a/src/main/java/cc/fascinated/bat/features/counter/command/SetupSubCommand.java b/src/main/java/cc/fascinated/bat/features/counter/command/SetupSubCommand.java new file mode 100644 index 0000000..9180637 --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/counter/command/SetupSubCommand.java @@ -0,0 +1,67 @@ +package cc.fascinated.bat.features.counter.command; + +import cc.fascinated.bat.Emojis; +import cc.fascinated.bat.command.BatCommand; +import cc.fascinated.bat.command.CommandInfo; +import cc.fascinated.bat.common.EmbedUtils; +import cc.fascinated.bat.features.counter.CounterProfile; +import cc.fascinated.bat.model.BatGuild; +import cc.fascinated.bat.model.BatUser; +import lombok.NonNull; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.channel.ChannelType; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; +import net.dv8tion.jda.api.entities.channel.unions.GuildChannelUnion; +import net.dv8tion.jda.api.interactions.commands.OptionMapping; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction; +import net.dv8tion.jda.api.interactions.commands.build.OptionData; +import org.springframework.stereotype.Component; + +/** + * @author Fascinated (fascinated7) + */ +@Component("counter.setup:sub") +@CommandInfo(name = "setup", description = "Setup a counter for a channel") +public class SetupSubCommand extends BatCommand { + public SetupSubCommand() { + super.addOptions(new OptionData(OptionType.CHANNEL, "channel", "The channel to setup the counter in", true)); + super.addOptions(new OptionData(OptionType.BOOLEAN, "breakable", "Should the channel break on a invalid or wrong number", true)); + } + + @Override + public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) { + OptionMapping channelOption = event.getOption("channel"); + OptionMapping breakableOption = event.getOption("breakable"); + if (channelOption == null || breakableOption == null) { + return; + } + + GuildChannelUnion targetChannel = channelOption.getAsChannel(); + if (targetChannel.getType() != ChannelType.TEXT) { + event.replyEmbeds(EmbedUtils.errorEmbed() + .setDescription("%s The channel must be a text channel".formatted(Emojis.CROSS_MARK_EMOJI)) + .build()).queue(); + return; + } + + TextChannel textChannel = targetChannel.asTextChannel(); + CounterProfile profile = guild.getCounterProfile(); + if (profile.getCounterChannel(textChannel.getId()) != null) { + event.replyEmbeds(EmbedUtils.errorEmbed() + .setDescription("%s This channel is already a counter channel".formatted(Emojis.CROSS_MARK_EMOJI)) + .build()).queue(); + return; + } + + boolean breakable = breakableOption.getAsBoolean(); + profile.setupChannel(textChannel, breakable); + event.replyEmbeds(EmbedUtils.successEmbed() + .setDescription("%s Successfully setup the counter in %s".formatted( + Emojis.CHECK_MARK_EMOJI, + textChannel.getAsMention() + )) + .build()).queue(); + } +} diff --git a/src/main/java/cc/fascinated/bat/model/BatGuild.java b/src/main/java/cc/fascinated/bat/model/BatGuild.java index e8c8031..85c0a17 100644 --- a/src/main/java/cc/fascinated/bat/model/BatGuild.java +++ b/src/main/java/cc/fascinated/bat/model/BatGuild.java @@ -5,6 +5,7 @@ import cc.fascinated.bat.common.ProfileHolder; import cc.fascinated.bat.common.Serializable; import cc.fascinated.bat.features.base.profile.FeatureProfile; import cc.fascinated.bat.features.birthday.profile.BirthdayProfile; +import cc.fascinated.bat.features.counter.CounterProfile; import cc.fascinated.bat.features.logging.LogProfile; import cc.fascinated.bat.features.namehistory.profile.guild.NameHistoryProfile; import cc.fascinated.bat.features.reminder.ReminderProfile; @@ -150,6 +151,15 @@ public class BatGuild extends ProfileHolder { return getProfile(WelcomerProfile.class); } + /** + * Gets the counter profile + * + * @return the counter profile + */ + public CounterProfile getCounterProfile() { + return getProfile(CounterProfile.class); + } + /** * Saves the user */