Search in sources :

Example 11 with Reason

use of com.sx4.bot.entities.mod.Reason in project Sx4 by sx4-discord-bot.

the class TemporaryBanManager method removeBanAndGet.

public DeleteOneModel<Document> removeBanAndGet(long guildId, long userId, boolean automatic) {
    ShardManager shardManager = this.bot.getShardManager();
    Guild guild = shardManager.getGuildById(guildId);
    if (guild == null) {
        return null;
    }
    User user = shardManager.getUserById(userId);
    Member member = user == null ? null : guild.getMember(user);
    if (automatic && member == null) {
        guild.unban(String.valueOf(userId)).reason("Ban length served").queue();
    }
    if (automatic) {
        Reason reason = new Reason("Ban length served");
        UnbanEvent event = new UnbanEvent(guild.getSelfMember(), user == null ? User.fromId(userId) : user, reason);
        this.bot.getModActionManager().onModAction(event);
    }
    this.deleteExecutor(guildId, userId);
    return new DeleteOneModel<>(Filters.and(Filters.eq("guildId", guildId), Filters.eq("userId", userId)));
}
Also used : User(net.dv8tion.jda.api.entities.User) UnbanEvent(com.sx4.bot.events.mod.UnbanEvent) ShardManager(net.dv8tion.jda.api.sharding.ShardManager) Guild(net.dv8tion.jda.api.entities.Guild) Member(net.dv8tion.jda.api.entities.Member) Reason(com.sx4.bot.entities.mod.Reason)

Example 12 with Reason

use of com.sx4.bot.entities.mod.Reason in project Sx4 by sx4-discord-bot.

the class AntiRegexHandler method handle.

public void handle(Message message) {
    Member member = message.getMember();
    if (member == null) {
        return;
    }
    User user = member.getUser();
    if (user.isBot()) {
        return;
    }
    Guild guild = message.getGuild();
    Member selfMember = guild.getSelfMember();
    TextChannel textChannel = message.getTextChannel();
    long guildId = guild.getIdLong(), userId = member.getIdLong(), channelId = textChannel.getIdLong();
    Category parent = textChannel.getParent();
    List<Role> roles = member.getRoles();
    String content = message.getContentRaw();
    List<Bson> guildPipeline = List.of(Aggregates.project(Projections.fields(Projections.computed("premium", Operators.lt(Operators.nowEpochSecond(), Operators.ifNull("$premium.endAt", 0L))), Projections.computed("guildId", "$_id"))), Aggregates.match(Filters.eq("guildId", guild.getIdLong())));
    List<Bson> pipeline = List.of(Aggregates.match(Filters.and(Filters.eq("guildId", guild.getIdLong()), Filters.exists("enabled", false))), Aggregates.group(null, Accumulators.push("regexes", Operators.ROOT)), Aggregates.unionWith("guilds", guildPipeline), Aggregates.group(null, Accumulators.max("premium", "$premium"), Accumulators.max("regexes", "$regexes")), Aggregates.project(Projections.computed("regexes", Operators.let(new Document("regexes", Operators.ifNull("$regexes", Collections.EMPTY_LIST)), Operators.cond(Operators.ifNull("$premium", false), "$$regexes", Operators.concatArrays(Operators.filter("$$regexes", Operators.ne("$$this.type", RegexType.REGEX.getId())), Operators.slice(Operators.filter("$$regexes", Operators.eq("$$this.type", RegexType.REGEX.getId())), 0, 3)))))));
    this.bot.getMongo().aggregateRegexes(pipeline).whenComplete((documents, exception) -> {
        if (documents.isEmpty()) {
            return;
        }
        Document data = documents.get(0);
        this.executor.submit(() -> {
            List<CompletableFuture<Document>> matches = new ArrayList<>();
            Regexes: for (Document regex : data.getList("regexes", Document.class)) {
                if (member.hasPermission(Permission.ADMINISTRATOR) && regex.getBoolean("admin", true)) {
                    continue;
                }
                List<Document> channels = regex.getList("whitelist", Document.class, Collections.emptyList());
                Document channel = channels.stream().filter(d -> (d.getInteger("type") == WhitelistType.CHANNEL.getId() && d.getLong("id") == channelId) || (d.getInteger("type") == WhitelistType.CATEGORY.getId() && parent != null && d.getLong("id") == parent.getIdLong())).min(Comparator.comparingInt(d -> d.getInteger("type", 0))).orElse(MongoDatabase.EMPTY_DOCUMENT);
                List<Document> holders = channel.getList("holders", Document.class, Collections.emptyList());
                for (Document holder : holders) {
                    long holderId = holder.getLong("id");
                    int type = holder.getInteger("type");
                    if (type == HolderType.USER.getType() && userId == holderId) {
                        continue Regexes;
                    } else if (type == HolderType.ROLE.getType() && (guildId == holderId || roles.stream().anyMatch(role -> role.getIdLong() == holderId))) {
                        continue Regexes;
                    }
                }
                RegexType type = RegexType.fromId(regex.getInteger("type"));
                Pattern pattern = type == RegexType.REGEX ? Pattern.compile(regex.getString("pattern")) : this.invitePattern;
                Matcher matcher;
                try {
                    matcher = this.executor.submit(() -> pattern.matcher(content)).get(2000, TimeUnit.MILLISECONDS);
                } catch (TimeoutException | InterruptedException | ExecutionException e) {
                    continue;
                }
                Set<String> codes = new HashSet<>();
                int matchCount = 0, totalCount = 0;
                while (matcher.find()) {
                    List<Document> groups = channel.getList("groups", Document.class, Collections.emptyList());
                    for (Document group : groups) {
                        List<String> strings = group.getList("strings", String.class, Collections.emptyList());
                        String match = matcher.group(group.getInteger("group"));
                        if (match != null && strings.contains(match)) {
                            matchCount++;
                        }
                    }
                    if (type == RegexType.INVITE) {
                        codes.add(matcher.group(1));
                    }
                    totalCount++;
                }
                if (matchCount == totalCount) {
                    continue;
                }
                CompletableFuture<Document> future;
                if (type == RegexType.INVITE) {
                    List<CompletableFuture<Invite>> futures = codes.stream().map(code -> Invite.resolve(message.getJDA(), code, true).submit()).collect(Collectors.toList());
                    List<Long> guilds = channel.getList("guilds", Long.class, Collections.emptyList());
                    future = FutureUtility.anyOf(futures, invite -> {
                        Invite.Guild inviteGuild = invite.getGuild();
                        return inviteGuild == null || (!guilds.contains(inviteGuild.getIdLong()) && inviteGuild.getIdLong() != guildId);
                    }).thenApply(invite -> invite == null ? null : regex);
                } else {
                    future = CompletableFuture.completedFuture(regex);
                }
                matches.add(future);
            }
            FutureUtility.anyOf(matches, Objects::nonNull).thenAccept(regex -> {
                if (regex == null) {
                    return;
                }
                ObjectId id = regex.getObjectId("_id");
                RegexType type = RegexType.fromId(regex.getInteger("type"));
                Document match = regex.get("match", MongoDatabase.EMPTY_DOCUMENT);
                long matchAction = match.get("action", MatchAction.ALL);
                Document mod = regex.get("mod", MongoDatabase.EMPTY_DOCUMENT);
                Document actionData = mod.get("action", Document.class);
                Action action = actionData == null ? null : Action.fromData(actionData);
                Document attempts = regex.get("attempts", MongoDatabase.EMPTY_DOCUMENT);
                int maxAttempts = attempts.get("amount", 3);
                if ((matchAction & MatchAction.DELETE_MESSAGE.getRaw()) == MatchAction.DELETE_MESSAGE.getRaw() && selfMember.hasPermission(textChannel, Permission.MESSAGE_MANAGE)) {
                    message.delete().queue();
                }
                Document reset = attempts.get("reset", Document.class);
                List<Bson> update = List.of(Operators.set("attempts", Operators.let(new Document("attempts", Operators.ifNull("$attempts", 0)), Operators.cond(Operators.exists("$reset"), Operators.max(1, Operators.add(1, Operators.subtract("$$attempts", Operators.multiply(Operators.toInt(Operators.floor(Operators.divide(Operators.subtract(Operators.nowEpochSecond(), "$lastAttempt"), "$reset.after"))), "$reset.amount")))), Operators.add("$$attempts", 1)))), Operators.set("lastAttempt", Operators.nowEpochSecond()), Operators.setOnInsert("guildId", guildId), reset == null ? Operators.unset("reset") : Operators.set("reset", reset));
                Bson filter = Filters.and(Filters.eq("userId", userId), Filters.eq("regexId", id));
                FindOneAndUpdateOptions options = new FindOneAndUpdateOptions().upsert(true).projection(Projections.include("attempts")).returnDocument(ReturnDocument.AFTER);
                this.bot.getMongo().findAndUpdateRegexAttempt(filter, update, options).whenComplete((attemptsData, attemptsException) -> {
                    if (ExceptionUtility.sendErrorMessage(attemptsException)) {
                        return;
                    }
                    int currentAttempts = attemptsData.getInteger("attempts", 0);
                    String matchMessage = this.format(match.get("message", type.getDefaultMatchMessage()), user, textChannel, id, currentAttempts, maxAttempts, action);
                    String modMessage = this.format(mod.get("message", type.getDefaultModMessage()), user, textChannel, id, currentAttempts, maxAttempts, action);
                    boolean send = (matchAction & MatchAction.SEND_MESSAGE.getRaw()) == MatchAction.SEND_MESSAGE.getRaw() && selfMember.hasPermission(textChannel, Permission.MESSAGE_WRITE);
                    if (action != null && currentAttempts == maxAttempts) {
                        Reason reason = new Reason(String.format("Sent a message which matched regex `%s` %d time%s", id.toHexString(), maxAttempts, maxAttempts == 1 ? "" : "s"));
                        ModUtility.performAction(this.bot, action, member, selfMember, reason).thenCompose(result -> {
                            if (send) {
                                textChannel.sendMessage(modMessage).allowedMentions(EnumSet.allOf(Message.MentionType.class)).queue();
                            }
                            return this.bot.getMongo().deleteRegexAttempt(Filters.and(Filters.eq("userId", userId), Filters.eq("regexId", id)));
                        }).whenComplete((result, modException) -> {
                            Throwable cause = modException instanceof CompletionException ? modException.getCause() : modException;
                            if (cause instanceof ModException) {
                                textChannel.sendMessage(modException.getMessage() + " " + this.bot.getConfig().getFailureEmote()).queue();
                                return;
                            }
                            ExceptionUtility.sendExceptionally(textChannel, modException);
                        });
                        return;
                    }
                    if (send) {
                        textChannel.sendMessage(matchMessage).allowedMentions(EnumSet.allOf(Message.MentionType.class)).queue();
                    }
                });
            });
        });
    });
}
Also used : HolderType(com.sx4.bot.entities.settings.HolderType) Document(org.bson.Document) net.dv8tion.jda.api.entities(net.dv8tion.jda.api.entities) java.util(java.util) ModException(com.sx4.bot.exceptions.mod.ModException) Permission(net.dv8tion.jda.api.Permission) MongoDatabase(com.sx4.bot.database.mongo.MongoDatabase) MatchAction(com.sx4.bot.entities.mod.auto.MatchAction) Bson(org.bson.conversions.Bson) Matcher(java.util.regex.Matcher) Sx4(com.sx4.bot.core.Sx4) Reason(com.sx4.bot.entities.mod.Reason) GenericEvent(net.dv8tion.jda.api.events.GenericEvent) com.mongodb.client.model(com.mongodb.client.model) FutureUtility(com.sx4.bot.utility.FutureUtility) Action(com.sx4.bot.entities.mod.action.Action) GuildMessageReceivedEvent(net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent) Operators(com.sx4.bot.database.mongo.model.Operators) GuildMessageUpdateEvent(net.dv8tion.jda.api.events.message.guild.GuildMessageUpdateEvent) java.util.concurrent(java.util.concurrent) ModUtility(com.sx4.bot.utility.ModUtility) WhitelistType(com.sx4.bot.entities.management.WhitelistType) Collectors(java.util.stream.Collectors) EventListener(net.dv8tion.jda.api.hooks.EventListener) StringFormatter(com.sx4.bot.formatter.StringFormatter) ObjectId(org.bson.types.ObjectId) ExceptionUtility(com.sx4.bot.utility.ExceptionUtility) RegexType(com.sx4.bot.entities.mod.auto.RegexType) Pattern(java.util.regex.Pattern) NotNull(org.jetbrains.annotations.NotNull) RegexType(com.sx4.bot.entities.mod.auto.RegexType) MatchAction(com.sx4.bot.entities.mod.auto.MatchAction) Action(com.sx4.bot.entities.mod.action.Action) Matcher(java.util.regex.Matcher) ModException(com.sx4.bot.exceptions.mod.ModException) Document(org.bson.Document) Reason(com.sx4.bot.entities.mod.Reason) Bson(org.bson.conversions.Bson) Pattern(java.util.regex.Pattern) ObjectId(org.bson.types.ObjectId)

Example 13 with Reason

use of com.sx4.bot.entities.mod.Reason in project Sx4 by sx4-discord-bot.

the class SuggestionCommand method set.

@Command(value = "set", description = "Sets a suggestion to a specified state")
@CommandId(86)
@Examples({ "suggestion set 5e45ce6d3688b30ee75201ae pending Need some time to think about this", "suggestion set 5e45ce6d3688b30ee75201ae accepted I think this is a great idea", "suggestion 5e45ce6d3688b30ee75201ae set denied Not possible" })
@AuthorPermissions(permissions = { Permission.MANAGE_SERVER })
public void set(Sx4CommandEvent event, @Argument(value = "id | message", acceptEmpty = true) Or<ObjectId, MessageArgument> argument, @Argument(value = "state") String stateName, @Argument(value = "reason", endless = true, nullDefault = true) String reason) {
    Document data = event.getMongo().getGuildById(event.getGuild().getIdLong(), Projections.include("suggestion.states", "suggestion.webhook")).get("suggestion", MongoDatabase.EMPTY_DOCUMENT);
    List<Document> states = data.getList("states", Document.class, SuggestionState.DEFAULT_STATES);
    Document state = states.stream().filter(stateData -> stateData.getString("dataName").equalsIgnoreCase(stateName)).findFirst().orElse(null);
    if (state == null) {
        event.replyFailure("You do not have a suggestion state with that name").queue();
        return;
    }
    String stateData = state.getString("dataName");
    Bson update = Updates.combine(reason == null ? Updates.unset("reason") : Updates.set("reason", reason), Updates.set("state", stateData), Updates.set("moderatorId", event.getAuthor().getIdLong()));
    Bson filter = Filters.and(argument.hasFirst() ? Filters.eq("_id", argument.getFirst()) : Filters.eq("messageId", argument.getSecond().getMessageId()), Filters.eq("guildId", event.getGuild().getIdLong()));
    FindOneAndUpdateOptions options = new FindOneAndUpdateOptions().returnDocument(ReturnDocument.BEFORE).projection(Projections.include("channelId", "authorId", "reason", "state", "suggestion", "messageId", "image"));
    event.getMongo().findAndUpdateSuggestion(filter, update, options).whenComplete((suggestionData, exception) -> {
        if (ExceptionUtility.sendExceptionally(event, exception)) {
            return;
        }
        if (suggestionData == null) {
            event.replyFailure("There is no suggestion with that id").queue();
            return;
        }
        String reasonData = suggestionData.getString("reason");
        boolean reasonMatch = reasonData == null && reason == null || (reasonData != null && reasonData.equals(reason));
        if (suggestionData.getString("state").equals(stateData) && reasonMatch) {
            event.replyFailure("That suggestion is already in that state and has the same reason").queue();
            return;
        }
        TextChannel channel = event.getGuild().getTextChannelById(suggestionData.getLong("channelId"));
        if (channel == null) {
            event.replyFailure("The channel for that suggestion no longer exists").queue();
            return;
        }
        User author = event.getShardManager().getUserById(suggestionData.getLong("authorId"));
        long messageId = suggestionData.getLong("messageId");
        if (author != null) {
            author.openPrivateChannel().flatMap(privateChannel -> privateChannel.sendMessage("Your suggestion has been updated by a moderator, click the message link to view it\nhttps://discord.com/channels/" + event.getGuild().getIdLong() + "/" + channel.getIdLong() + "/" + messageId)).queue(null, ErrorResponseException.ignore(ErrorResponse.CANNOT_SEND_TO_USER));
        }
        WebhookEmbed embed = Suggestion.getWebhookEmbed(suggestionData.getObjectId("_id"), event.getAuthor(), author, suggestionData.getString("suggestion"), suggestionData.getString("image"), reason, new SuggestionState(state));
        event.getBot().getSuggestionManager().editSuggestion(messageId, channel.getIdLong(), data.get("webhook", MongoDatabase.EMPTY_DOCUMENT), embed);
        event.replySuccess("That suggestion has been set to the `" + stateData + "` state").queue();
    });
}
Also used : Document(org.bson.Document) CancelException(com.sx4.bot.waiter.exception.CancelException) WebhookClient(club.minnced.discord.webhook.WebhookClient) Command(com.jockie.bot.core.command.Command) ButtonClickEvent(net.dv8tion.jda.api.events.interaction.ButtonClickEvent) MessageArgument(com.sx4.bot.entities.argument.MessageArgument) Suggestion(com.sx4.bot.entities.management.Suggestion) Permission(net.dv8tion.jda.api.Permission) MongoDatabase(com.sx4.bot.database.mongo.MongoDatabase) TextChannel(net.dv8tion.jda.api.entities.TextChannel) ErrorResponse(net.dv8tion.jda.api.requests.ErrorResponse) PagedResult(com.sx4.bot.paged.PagedResult) User(net.dv8tion.jda.api.entities.User) Bson(org.bson.conversions.Bson) Alternative(com.sx4.bot.entities.argument.Alternative) ColourUtility(com.sx4.bot.utility.ColourUtility) ButtonUtility(com.sx4.bot.utility.ButtonUtility) WebhookEmbed(club.minnced.discord.webhook.send.WebhookEmbed) Sx4CommandEvent(com.sx4.bot.core.Sx4CommandEvent) Button(net.dv8tion.jda.api.interactions.components.Button) AlternativeOptions(com.sx4.bot.annotations.argument.AlternativeOptions) Waiter(com.sx4.bot.waiter.Waiter) GenericEvent(net.dv8tion.jda.api.events.GenericEvent) com.mongodb.client.model(com.mongodb.client.model) com.sx4.bot.annotations.command(com.sx4.bot.annotations.command) Or(com.sx4.bot.entities.argument.Or) Argument(com.jockie.bot.core.argument.Argument) Message(net.dv8tion.jda.api.entities.Message) Operators(com.sx4.bot.database.mongo.model.Operators) ErrorResponseException(net.dv8tion.jda.api.exceptions.ErrorResponseException) Sx4Command(com.sx4.bot.core.Sx4Command) CompletionException(java.util.concurrent.CompletionException) TimeoutException(com.sx4.bot.waiter.exception.TimeoutException) Colour(com.sx4.bot.annotations.argument.Colour) ModuleCategory(com.sx4.bot.category.ModuleCategory) List(java.util.List) ImageUrl(com.sx4.bot.annotations.argument.ImageUrl) ObjectId(org.bson.types.ObjectId) Clock(java.time.Clock) ExceptionUtility(com.sx4.bot.utility.ExceptionUtility) SuggestionState(com.sx4.bot.entities.management.SuggestionState) Collections(java.util.Collections) TextChannel(net.dv8tion.jda.api.entities.TextChannel) WebhookEmbed(club.minnced.discord.webhook.send.WebhookEmbed) User(net.dv8tion.jda.api.entities.User) SuggestionState(com.sx4.bot.entities.management.SuggestionState) Document(org.bson.Document) Bson(org.bson.conversions.Bson) Command(com.jockie.bot.core.command.Command) Sx4Command(com.sx4.bot.core.Sx4Command)

Example 14 with Reason

use of com.sx4.bot.entities.mod.Reason in project Sx4 by sx4-discord-bot.

the class ModLogCommand method case_.

@Command(value = "case", description = "Edit the reason of a mod log case")
@CommandId(68)
@Examples({ "modlog case 5e45ce6d3688b30ee75201ae Spamming", "modlog case 5fc24ea34854845b7c74e7f4-5fc24ea64854845b7c74e7f6 template:tos", "modlog case 5e45ce6d3688b30ee75201ae,5e45ce6d3688b30ee75201ab t:tos and Spamming" })
public void case_(Sx4CommandEvent event, @Argument(value = "id(s)") Range<ObjectId> range, @Argument(value = "reason", endless = true) Reason reason) {
    List<Bson> or = new ArrayList<>();
    for (Pair<ObjectId, ObjectId> r : range.getRanges()) {
        or.add(Operators.and(Operators.gte(Operators.objectIdToEpochSecond("$_id"), r.getLeft().getTimestamp()), Operators.lte(Operators.objectIdToEpochSecond("$_id"), r.getRight().getTimestamp())));
    }
    for (ObjectId r : range.getObjects()) {
        or.add(Operators.eq("$_id", r));
    }
    long authorId = event.getAuthor().getIdLong();
    List<Bson> update = List.of(Operators.set("reason", Operators.cond(Operators.and(Operators.or(Operators.eq("$moderatorId", authorId), event.hasPermission(event.getMember(), Permission.ADMINISTRATOR)), Operators.or(or)), reason.getParsed(), "$reason")));
    event.getMongo().updateManyModLogs(Filters.eq("guildId", event.getGuild().getIdLong()), update).whenComplete((result, exception) -> {
        if (ExceptionUtility.sendExceptionally(event, exception)) {
            return;
        }
        long modified = result.getModifiedCount();
        if (modified == 0) {
            event.replyFailure("You were unable to update any of those mod logs or you provided an invalid range").queue();
            return;
        }
        event.replyFormat("Updated **%d** case%s %s", modified, modified == 1 ? "" : "s", event.getConfig().getSuccessEmote()).queue();
    });
}
Also used : ObjectId(org.bson.types.ObjectId) ArrayList(java.util.ArrayList) Bson(org.bson.conversions.Bson) Command(com.jockie.bot.core.command.Command) Sx4Command(com.sx4.bot.core.Sx4Command) CommandId(com.sx4.bot.annotations.command.CommandId) Examples(com.sx4.bot.annotations.command.Examples)

Example 15 with Reason

use of com.sx4.bot.entities.mod.Reason in project Sx4 by sx4-discord-bot.

the class TemplateCommand method add.

@Command(value = "add", description = "Add a template in the current server")
@CommandId(255)
@Examples({ "template add tos Broke ToS", "template add spam Spamming excessively" })
@AuthorPermissions(permissions = { Permission.MANAGE_SERVER })
public void add(Sx4CommandEvent event, @Argument(value = "template") @Limit(max = 100) String template, @Argument(value = "reason", endless = true) String reason) {
    Document data = new Document("template", template).append("reason", reason).append("guildId", event.getGuild().getIdLong());
    event.getMongo().insertTemplate(data).whenComplete((result, exception) -> {
        Throwable cause = exception instanceof CompletionException ? exception.getCause() : exception;
        if (cause instanceof MongoWriteException && ((MongoWriteException) cause).getError().getCategory() == ErrorCategory.DUPLICATE_KEY) {
            event.replyFailure("You already have a template with that name").queue();
            return;
        }
        if (ExceptionUtility.sendExceptionally(event, exception)) {
            return;
        }
        event.replySuccess("That template has been added with id `" + result.getInsertedId().asObjectId().getValue().toHexString() + "`").queue();
    });
}
Also used : MongoWriteException(com.mongodb.MongoWriteException) CompletionException(java.util.concurrent.CompletionException) Document(org.bson.Document) AuthorPermissions(com.sx4.bot.annotations.command.AuthorPermissions) Command(com.jockie.bot.core.command.Command) Sx4Command(com.sx4.bot.core.Sx4Command) CommandId(com.sx4.bot.annotations.command.CommandId) Examples(com.sx4.bot.annotations.command.Examples)

Aggregations

Document (org.bson.Document)11 Bson (org.bson.conversions.Bson)10 Reason (com.sx4.bot.entities.mod.Reason)8 User (net.dv8tion.jda.api.entities.User)8 Member (net.dv8tion.jda.api.entities.Member)7 com.mongodb.client.model (com.mongodb.client.model)6 Operators (com.sx4.bot.database.mongo.model.Operators)6 Permission (net.dv8tion.jda.api.Permission)6 Guild (net.dv8tion.jda.api.entities.Guild)6 MongoDatabase (com.sx4.bot.database.mongo.MongoDatabase)5 CompletionException (java.util.concurrent.CompletionException)5 Role (net.dv8tion.jda.api.entities.Role)5 ErrorResponseException (net.dv8tion.jda.api.exceptions.ErrorResponseException)5 ObjectId (org.bson.types.ObjectId)5 Command (com.jockie.bot.core.command.Command)4 Sx4 (com.sx4.bot.core.Sx4)4 Action (com.sx4.bot.entities.mod.action.Action)4 List (java.util.List)4 Sx4Command (com.sx4.bot.core.Sx4Command)3 com.sx4.bot.entities.mod.action (com.sx4.bot.entities.mod.action)3