Search in sources :

Example 1 with Message

use of net.dv8tion.jda.api.entities.Message in project MantaroBot by Mantaro.

the class ReactionOperations method addReactions.

private static void addReactions(Future<Void> future, Message message, String... defaultReactions) {
    AtomicInteger index = new AtomicInteger();
    AtomicReference<Consumer<Void>> c = new AtomicReference<>();
    Consumer<Throwable> ignore = (t) -> {
    };
    c.set(ignored -> {
        // Ignore this if we already cancelled this operation.
        if (future.isCancelled()) {
            return;
        }
        int i = index.incrementAndGet();
        if (i < defaultReactions.length) {
            message.addReaction(reaction(defaultReactions[i])).queue(c.get(), ignore);
        }
    });
    message.addReaction(reaction(defaultReactions[0])).queue(c.get(), ignore);
}
Also used : Message(net.dv8tion.jda.api.entities.Message) MessageReactionRemoveEvent(net.dv8tion.jda.api.events.message.react.MessageReactionRemoveEvent) ExpiringMap(net.jodah.expiringmap.ExpiringMap) CompletableFuture(java.util.concurrent.CompletableFuture) MessageReactionAddEvent(net.dv8tion.jda.api.events.message.react.MessageReactionAddEvent) AtomicReference(java.util.concurrent.atomic.AtomicReference) TimeUnit(java.util.concurrent.TimeUnit) Consumer(java.util.function.Consumer) MessageReactionRemoveAllEvent(net.dv8tion.jda.api.events.message.react.MessageReactionRemoveAllEvent) Future(java.util.concurrent.Future) EventListener(net.dv8tion.jda.api.hooks.EventListener) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) GenericEvent(net.dv8tion.jda.api.events.GenericEvent) ReactionOperation(net.kodehawa.mantarobot.core.listeners.operations.core.ReactionOperation) Operation(net.kodehawa.mantarobot.core.listeners.operations.core.Operation) Nonnull(javax.annotation.Nonnull) Consumer(java.util.function.Consumer) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) AtomicReference(java.util.concurrent.atomic.AtomicReference)

Example 2 with Message

use of net.dv8tion.jda.api.entities.Message in project MantaroBot by Mantaro.

the class BirthdayTask method handle.

public static void handle(int shardId) {
    final var bot = MantaroBot.getInstance();
    final var instant = Instant.now();
    try {
        final var cache = bot.getBirthdayCacher();
        // There's no cache to be seen here
        if (cache == null) {
            return;
        }
        // We haven't finished caching all members, somehow?
        if (!cache.isDone) {
            return;
        }
        final var start = System.currentTimeMillis();
        var membersAssigned = 0;
        var membersDivested = 0;
        final var jda = bot.getShardManager().getShardById(shardId);
        if (jda == null) {
            // To be fair, this shouldn't be possible as it only starts it with the shards it knows...
            return;
        }
        log.info("Checking birthdays in shard {} to assign roles...", jda.getShardInfo().getShardId());
        // Well, fuck, this was a day off. NYC time was 23:00 when Chicago time was at 00:00, so it checked the
        // birthdays for THE WRONG DAY. Heck.
        // 17-02-2022: Fuck again, I was using the wrong thing. Now it works, lol.
        final var timezone = ZonedDateTime.ofInstant(instant, ZoneId.of("America/Chicago"));
        // Example: 25-02
        final var now = timezone.format(dayMonthFormat);
        // Example: 02
        final var month = timezone.format(monthFormat);
        // Example: 01
        final var lastMonthTz = ZonedDateTime.ofInstant(instant, ZoneId.of("America/Chicago")).minusMonths(1);
        final var lastMonth = lastMonthTz.format(dateFormat);
        final var cached = cache.getCachedBirthdays();
        final var guilds = jda.getGuildCache();
        // Backoff sending: we need to backoff the birthday requests,
        // else we're gonna find ourselves quite often hitting ratelimits, which might slow the whole
        // bot down. Therefore, we're just gonna get all of the messages we need to send and *slowly*
        // send them over the course of a few minutes, instead of trying to send them all at once.
        Map<BirthdayGuildInfo, Queue<Message>> toSend = new HashMap<>();
        List<BirthdayRoleInfo> roleBackoffAdd = new ArrayList<>();
        List<BirthdayRoleInfo> roleBackoffRemove = new ArrayList<>();
        // For all current -cached- guilds.
        for (final var guild : guilds) {
            // This is quite a db spam, lol
            final var dbGuild = MantaroData.db().getGuild(guild);
            final var guildData = dbGuild.getData();
            // If we have a birthday guild and channel here, continue
            if (guildData.getBirthdayChannel() != null && guildData.getBirthdayRole() != null) {
                final var birthdayRole = guild.getRoleById(guildData.getBirthdayRole());
                final var channel = guild.getTextChannelById(guildData.getBirthdayChannel());
                if (channel != null && birthdayRole != null) {
                    if (!guild.getSelfMember().canInteract(birthdayRole))
                        // Go to next guild...
                        continue;
                    if (!channel.canTalk())
                        // cannot talk here...
                        continue;
                    if (guildData.getGuildAutoRole() != null && birthdayRole.getId().equals(guildData.getGuildAutoRole()))
                        // Birthday role is autorole role
                        continue;
                    if (birthdayRole.isPublicRole())
                        // Birthday role is public role
                        continue;
                    if (birthdayRole.isManaged())
                        // This was meant to be a bot role?
                        continue;
                    // Guild map is now created from allowed birthdays. This is a little hacky, but we don't really care.
                    // The other solution would have been just disabling this completely, which would have been worse.
                    // @formatter:off
                    Map<Long, BirthdayCacher.BirthdayData> guildMap = cached.entrySet().stream().filter(map -> guildData.getAllowedBirthdays().contains(String.valueOf(map.getKey()))).filter(map -> map.getValue().getBirthday().substring(3, 5).equals(month) || map.getValue().getBirthday().substring(3, 5).equals(lastMonth)).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
                    // @formatter:on
                    var birthdayAnnouncerText = new MessageBuilder();
                    birthdayAnnouncerText.append("**New birthdays for today, wish them Happy Birthday!**").append("\n\n");
                    int birthdayNumber = 0;
                    List<Long> nullMembers = new ArrayList<>();
                    for (var data : guildMap.entrySet()) {
                        var birthday = data.getValue().getBirthday();
                        if (guildData.getBirthdayBlockedIds().contains(String.valueOf(data.getKey()))) {
                            continue;
                        }
                        if (birthday == null) {
                            log.debug("Birthday is null? Continuing...");
                            nullMembers.add(data.getKey());
                            continue;
                        }
                        // This needs to be a retrieveMemberById call, sadly. This will get cached, though.
                        Member member;
                        try {
                            // This is expensive!
                            member = guild.retrieveMemberById(data.getKey(), false).complete();
                        } catch (Exception ex) {
                            nullMembers.add(data.getKey());
                            continue;
                        }
                        // Make sure we announce on March 1st for birthdays on February 29 if the current
                        // year is not a leap year.
                        var compare = birthday.substring(0, 5);
                        if (compare.equals("29-02") && !Year.isLeap(LocalDate.now().getYear())) {
                            compare = "28-02";
                        }
                        if (compare.equals(now)) {
                            log.debug("Assigning birthday role on guild {} (M: {})", guild.getId(), member.getEffectiveName());
                            var tempBirthdayMessage = String.format(EmoteReference.POPPER + "**%s is a year older now! Wish them a happy birthday.** :tada:", member.getEffectiveName());
                            if (guildData.getBirthdayMessage() != null) {
                                tempBirthdayMessage = guildData.getBirthdayMessage().replace("$(user)", member.getEffectiveName()).replace("$(usermention)", member.getAsMention()).replace("$(tag)", member.getUser().getAsTag());
                            }
                            // Variable used in lambda expression should be final or effectively final...
                            final var birthdayMessage = tempBirthdayMessage;
                            if (!member.getRoles().contains(birthdayRole)) {
                                log.debug("Backing off adding birthday role on guild {} (M: {})", guild.getId(), member.getEffectiveName());
                                // We can pretty much do all of this only based on the IDs
                                roleBackoffAdd.add(new BirthdayRoleInfo(guild.getId(), member.getId(), birthdayRole));
                                birthdayAnnouncerText.append(birthdayMessage).append("\n");
                                membersAssigned++;
                                birthdayNumber++;
                                Metrics.BIRTHDAY_COUNTER.inc();
                            }
                        } else {
                            // day passed
                            if (member.getRoles().contains(birthdayRole)) {
                                log.debug("Backing off removing birthday role on guild {} (M: {})", guild.getId(), member.getEffectiveName());
                                roleBackoffRemove.add(new BirthdayRoleInfo(guild.getId(), member.getId(), birthdayRole));
                                membersDivested++;
                            }
                        }
                    }
                    if (birthdayNumber != 0) {
                        toSend.put(new BirthdayGuildInfo(guild.getId(), channel.getId()), birthdayAnnouncerText.buildAll(MessageBuilder.SplitPolicy.NEWLINE));
                    }
                    // If any of the member lookups to discord returned null, remove them.
                    if (!nullMembers.isEmpty()) {
                        guildData.getAllowedBirthdays().removeAll(nullMembers.stream().map(String::valueOf).collect(Collectors.toList()));
                        dbGuild.save();
                    }
                }
            }
        }
        final var end = System.currentTimeMillis();
        log.info("{} (birthdays): people assigned: {}, people divested: {}, took {}ms", jda.getShardInfo(), membersAssigned, membersDivested, (end - start));
        // A poll inside a pool?
        // Send the backoff sending comment above, this basically avoids hitting
        // discord with one billion requests at once.
        final var backoff = 400;
        final var roleBackoff = 100;
        backOffPool.submit(() -> {
            log.info("{} (birthdays): Backoff messages: {}. Sending them with {}ms backoff.", jda.getShardInfo(), toSend.size(), backoff);
            final var startMessage = System.currentTimeMillis();
            for (var entry : toSend.entrySet()) {
                try {
                    final var info = entry.getKey();
                    final var guildId = info.guildId;
                    final var channelId = info.channelId;
                    final var messages = entry.getValue();
                    final var guild = bot.getShardManager().getGuildById(guildId);
                    if (guild == null)
                        continue;
                    final var channel = guild.getTextChannelById(channelId);
                    if (channel == null)
                        continue;
                    messages.forEach(message -> channel.sendMessage(message).allowedMentions(EnumSet.of(Message.MentionType.USER, Message.MentionType.CHANNEL, Message.MentionType.ROLE, Message.MentionType.EMOTE)).queue());
                    // If 100 guilds (about 1/10th of all the shard guilds! so very unlikely) do
                    // get a birthday now, the maximum delay will be 40,000ms, which is 40 seconds.
                    // Not much of an issue for the end user, but avoid sending too many requests
                    // to discord at once. If half of all the guilds in the shard do, the delay
                    // will be about 200,000ms, so 2 minutes.
                    Thread.sleep(backoff);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            final var endMessage = System.currentTimeMillis();
            toSend.clear();
            log.info("Sent all birthday backoff messages, backoff was {}ms, took {}ms", backoff, endMessage - startMessage);
        });
        backOffRolePool.submit(() -> {
            log.info("{} (birthdays): Backoff roles (add): {}. Sending them with {}ms backoff.", jda.getShardInfo(), roleBackoffAdd.size(), roleBackoff);
            final var startRole = System.currentTimeMillis();
            for (var roleInfo : roleBackoffAdd) {
                try {
                    var guild = bot.getShardManager().getGuildById(roleInfo.guildId);
                    if (guild == null)
                        continue;
                    guild.addRoleToMember(roleInfo.memberId, roleInfo.role).reason(modLogMessage).queue();
                    Thread.sleep(roleBackoff);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            log.info("{} (birthdays): Backoff roles (remove): {}. Sending them with {}ms backoff.", jda.getShardInfo(), roleBackoffRemove.size(), roleBackoff);
            for (var roleInfo : roleBackoffRemove) {
                try {
                    var guild = bot.getShardManager().getGuildById(roleInfo.guildId);
                    if (guild == null)
                        continue;
                    guild.removeRoleFromMember(roleInfo.memberId, roleInfo.role).reason(modLogMessage).queue();
                    Thread.sleep(roleBackoff);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            final var endRole = System.currentTimeMillis();
            roleBackoffAdd.clear();
            roleBackoffRemove.clear();
            log.info("{} (birthdays): All roles done (add and removal), backoff was {}ms. Took {}ms", jda.getShardInfo(), roleBackoff, endRole - startRole);
        });
    } catch (Exception e) {
        e.printStackTrace();
    }
}
Also used : ThreadFactoryBuilder(com.google.common.util.concurrent.ThreadFactoryBuilder) Message(net.dv8tion.jda.api.entities.Message) java.util(java.util) Logger(org.slf4j.Logger) LoggerFactory(org.slf4j.LoggerFactory) Member(net.dv8tion.jda.api.entities.Member) Metrics(net.kodehawa.mantarobot.utils.exporters.Metrics) Collectors(java.util.stream.Collectors) Executors(java.util.concurrent.Executors) MantaroBot(net.kodehawa.mantarobot.MantaroBot) java.time(java.time) MessageBuilder(net.dv8tion.jda.api.MessageBuilder) Role(net.dv8tion.jda.api.entities.Role) EmoteReference(net.kodehawa.mantarobot.utils.commands.EmoteReference) DateTimeFormatter(java.time.format.DateTimeFormatter) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) MantaroData(net.kodehawa.mantarobot.data.MantaroData) MessageBuilder(net.dv8tion.jda.api.MessageBuilder) Member(net.dv8tion.jda.api.entities.Member)

Example 3 with Message

use of net.dv8tion.jda.api.entities.Message in project MantaroBot by Mantaro.

the class MessageCmds method prune.

@Subscribe
public void prune(CommandRegistry cr) {
    var pruneCmd = cr.register("prune", new TreeCommand(CommandCategory.MODERATION) {

        @Override
        public Command defaultTrigger(Context context, String mainCommand, String commandName) {
            return new SubCommand() {

                @Override
                protected void call(Context ctx, I18nContext languageContext, String content) {
                    var args = ctx.getArguments();
                    if (content.isEmpty()) {
                        ctx.sendLocalized("commands.prune.no_messages_specified", EmoteReference.ERROR);
                        return;
                    }
                    var mentionedUsers = ctx.getMentionedUsers();
                    var amount = 5;
                    if (args.length > 0) {
                        try {
                            amount = Integer.parseInt(args[0]);
                            if (amount < 3) {
                                amount = 3;
                            }
                        } catch (Exception e) {
                            ctx.sendLocalized("commands.prune.not_valid", EmoteReference.ERROR);
                            return;
                        }
                    }
                    if (!mentionedUsers.isEmpty()) {
                        List<Long> users = mentionedUsers.stream().map(User::getIdLong).collect(Collectors.toList());
                        final var finalAmount = amount;
                        ctx.getChannel().getHistory().retrievePast(100).queue(messageHistory -> getMessageHistory(ctx, messageHistory, finalAmount, "commands.prune.mention_no_messages", message -> users.contains(message.getAuthor().getIdLong())), error -> ctx.sendLocalized("commands.prune.error_retrieving", EmoteReference.ERROR, error.getClass().getSimpleName(), error.getMessage()));
                        return;
                    }
                    ctx.getChannel().getHistory().retrievePast(Math.min(amount, 100)).queue(messageHistory -> prune(ctx, messageHistory), error -> {
                        ctx.sendLocalized("commands.prune.error_retrieving", EmoteReference.ERROR, error.getClass().getSimpleName(), error.getMessage());
                        error.printStackTrace();
                    });
                }
            };
        }

        @Override
        public HelpContent help() {
            return new HelpContent.Builder().setDescription("Prunes X amount of messages from a channel. Requires Message Manage permission.").setUsage("`~>prune <messages> [@user...]`").addParameter("messages", "Number of messages from 4 to 100.").addParameterOptional("@user...", "Prunes messages only from mentioned users.").build();
        }
    });
    pruneCmd.setPredicate(ctx -> {
        if (!ctx.getMember().hasPermission(Permission.MESSAGE_MANAGE)) {
            ctx.sendLocalized("commands.prune.no_permissions_user", EmoteReference.ERROR);
            return false;
        }
        if (!ctx.getSelfMember().hasPermission(Permission.MESSAGE_MANAGE)) {
            ctx.sendLocalized("commands.prune.no_permissions", EmoteReference.ERROR);
            return false;
        }
        return true;
    });
    pruneCmd.addSubCommand("bot", new SubCommand() {

        @Override
        public String description() {
            return "Prune bot messages. It takes the number of messages as an argument.";
        }

        @Override
        protected void call(Context ctx, I18nContext languageContext, String content) {
            var args = ctx.getArguments();
            var amount = 100;
            if (args.length >= 1) {
                try {
                    amount = Integer.parseInt(args[0]);
                    if (amount < 3) {
                        amount = 3;
                    }
                } catch (Exception e) {
                    ctx.sendLocalized("commands.prune.not_valid", EmoteReference.ERROR);
                    return;
                }
            }
            final var finalAmount = amount;
            ctx.getChannel().getHistory().retrievePast(100).queue(messageHistory -> {
                String prefix = MantaroData.db().getGuild(ctx.getGuild()).getData().getGuildCustomPrefix();
                getMessageHistory(ctx, messageHistory, finalAmount, "commands.prune.bots_no_messages", message -> message.getAuthor().isBot() || message.getContentRaw().startsWith(prefix == null ? "~>" : prefix));
            }, error -> {
                ctx.sendLocalized("commands.prune.error_retrieving", EmoteReference.ERROR, error.getClass().getSimpleName(), error.getMessage());
                error.printStackTrace();
            });
        }
    });
    pruneCmd.addSubCommand("nopins", new SubCommand() {

        @Override
        public String description() {
            return "Prune messages that aren't pinned. It takes the number of messages as an argument.";
        }

        @Override
        protected void call(Context ctx, I18nContext languageContext, String content) {
            var args = ctx.getArguments();
            var amount = 100;
            if (args.length >= 1) {
                try {
                    amount = Integer.parseInt(args[0]);
                    if (amount < 3) {
                        amount = 3;
                    }
                } catch (Exception e) {
                    ctx.sendLocalized("commands.prune.not_valid", EmoteReference.ERROR);
                    return;
                }
            }
            final var finalAmount = amount;
            ctx.getChannel().getHistory().retrievePast(100).queue(messageHistory -> getMessageHistory(ctx, messageHistory, finalAmount, "commands.prune.no_pins_no_messages", message -> !message.isPinned()), error -> {
                ctx.sendLocalized("commands.prune.error_retrieving", EmoteReference.ERROR, error.getClass().getSimpleName(), error.getMessage());
                error.printStackTrace();
            });
        }
    });
}
Also used : I18nContext(net.kodehawa.mantarobot.core.modules.commands.i18n.I18nContext) Context(net.kodehawa.mantarobot.core.modules.commands.base.Context) Message(net.dv8tion.jda.api.entities.Message) Module(net.kodehawa.mantarobot.core.modules.Module) SubCommand(net.kodehawa.mantarobot.core.modules.commands.SubCommand) PermissionException(net.dv8tion.jda.api.exceptions.PermissionException) Command(net.kodehawa.mantarobot.core.modules.commands.base.Command) HelpContent(net.kodehawa.mantarobot.core.modules.commands.help.HelpContent) Predicate(java.util.function.Predicate) Permission(net.dv8tion.jda.api.Permission) Collectors(java.util.stream.Collectors) User(net.dv8tion.jda.api.entities.User) TreeCommand(net.kodehawa.mantarobot.core.modules.commands.TreeCommand) ModLog(net.kodehawa.mantarobot.commands.moderation.ModLog) List(java.util.List) OffsetDateTime(java.time.OffsetDateTime) CommandCategory(net.kodehawa.mantarobot.core.modules.commands.base.CommandCategory) I18nContext(net.kodehawa.mantarobot.core.modules.commands.i18n.I18nContext) CommandRegistry(net.kodehawa.mantarobot.core.CommandRegistry) EmoteReference(net.kodehawa.mantarobot.utils.commands.EmoteReference) MantaroData(net.kodehawa.mantarobot.data.MantaroData) Subscribe(com.google.common.eventbus.Subscribe) Context(net.kodehawa.mantarobot.core.modules.commands.base.Context) SubCommand(net.kodehawa.mantarobot.core.modules.commands.SubCommand) User(net.dv8tion.jda.api.entities.User) HelpContent(net.kodehawa.mantarobot.core.modules.commands.help.HelpContent) PermissionException(net.dv8tion.jda.api.exceptions.PermissionException) SubCommand(net.kodehawa.mantarobot.core.modules.commands.SubCommand) Command(net.kodehawa.mantarobot.core.modules.commands.base.Command) TreeCommand(net.kodehawa.mantarobot.core.modules.commands.TreeCommand) List(java.util.List) TreeCommand(net.kodehawa.mantarobot.core.modules.commands.TreeCommand) I18nContext(net.kodehawa.mantarobot.core.modules.commands.i18n.I18nContext) Subscribe(com.google.common.eventbus.Subscribe)

Example 4 with Message

use of net.dv8tion.jda.api.entities.Message in project c0debaseBot by Biospheere.

the class RoleStatsCommand method execute.

@Override
public void execute(final String[] args, final Message message) {
    final Guild guild = message.getGuild();
    final EmbedBuilder embedBuilder = getEmbed(guild, message.getAuthor()).setTitle("Rollen Statistiken");
    final Map<Role, Long> roles = guild.getMembers().stream().filter(member -> PermissionUtil.canInteract(guild.getSelfMember(), member)).map(member -> member.getRoles()).flatMap(stream -> stream.stream().filter(role -> (!role.isManaged() && !FORBIDDEN.contains(role.getName())))).collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
    embedBuilder.appendDescription("\n__**Rollen:**__\n\n");
    appendStats(roles, embedBuilder, false);
    embedBuilder.appendDescription("\n__**Farb-Rollen:**__\n\n");
    appendStats(roles, embedBuilder, true);
    message.getTextChannel().sendMessage(embedBuilder.build()).queue();
}
Also used : Role(net.dv8tion.jda.api.entities.Role) Message(net.dv8tion.jda.api.entities.Message) java.util(java.util) Guild(net.dv8tion.jda.api.entities.Guild) Role(net.dv8tion.jda.api.entities.Role) EmbedBuilder(net.dv8tion.jda.api.EmbedBuilder) Function(java.util.function.Function) Collectors(java.util.stream.Collectors) Command(de.c0debase.bot.commands.Command) PermissionUtil(net.dv8tion.jda.internal.utils.PermissionUtil) EmbedBuilder(net.dv8tion.jda.api.EmbedBuilder) Guild(net.dv8tion.jda.api.entities.Guild)

Example 5 with Message

use of net.dv8tion.jda.api.entities.Message in project c0debaseBot by Biospheere.

the class SetColorCommand method listAvailableColors.

private void listAvailableColors(Message message) {
    final EmbedBuilder embedBuilder = getEmbed(message.getGuild(), message.getAuthor());
    embedBuilder.setFooter("!setColor <Farbe>", message.getMember().getUser().getEffectiveAvatarUrl());
    embedBuilder.appendDescription("__**Es gibt diese Farben:**__\n\n");
    message.getGuild().getRoles().stream().map(Role::getName).filter(roleName -> roleName.startsWith("Color")).forEach(roleName -> embedBuilder.appendDescription(String.format("***%s***\n", roleName.replace("Color-", ""))));
    message.getTextChannel().sendMessage(embedBuilder.build()).queue();
}
Also used : Role(net.dv8tion.jda.api.entities.Role) Message(net.dv8tion.jda.api.entities.Message) List(java.util.List) Role(net.dv8tion.jda.api.entities.Role) EmbedBuilder(net.dv8tion.jda.api.EmbedBuilder) Collectors(java.util.stream.Collectors) Command(de.c0debase.bot.commands.Command) EmbedBuilder(net.dv8tion.jda.api.EmbedBuilder)

Aggregations

Message (net.dv8tion.jda.api.entities.Message)18 Collectors (java.util.stream.Collectors)7 EmbedBuilder (net.dv8tion.jda.api.EmbedBuilder)7 java.util (java.util)5 ScheduleEntry (ws.nmathe.saber.core.schedule.ScheduleEntry)5 JDA (net.dv8tion.jda.api.JDA)4 Permission (net.dv8tion.jda.api.Permission)4 Role (net.dv8tion.jda.api.entities.Role)4 TextChannel (net.dv8tion.jda.api.entities.TextChannel)4 java.time (java.time)3 TimeUnit (java.util.concurrent.TimeUnit)3 Consumer (java.util.function.Consumer)3 MessageBuilder (net.dv8tion.jda.api.MessageBuilder)3 Guild (net.dv8tion.jda.api.entities.Guild)3 Member (net.dv8tion.jda.api.entities.Member)3 MantaroData (net.kodehawa.mantarobot.data.MantaroData)3 EmoteReference (net.kodehawa.mantarobot.utils.commands.EmoteReference)3 Document (org.bson.Document)3 Main (ws.nmathe.saber.Main)3 Logging (ws.nmathe.saber.utils.Logging)3