Wie erstelle ich einen Discord Moderation Bot in Java?

Erstellen eines einfachen Moderationsbots

In diesem Tutorial wird davon ausgegangen, dass Sie Grundkenntnisse in JDA haben. Wenn Sie nicht wissen, wie Sie ein Projekt einrichten, lesen Sie dieses Tutorial

Schritt 1

Erstellen Sie ein neues Projekt und fügen Sie JDA als Abhängigkeit hinzu.

In diesem Lernprogramm verwenden wir JDA-Utilities, um unsere Befehle zu verarbeiten. Fügen Sie diese also auch als Abhängigkeit hinzu. Überprüfen Sie die neueste Version hier.

Unser build.gradle sieht jetzt so aus:

Plugins {
    id'java '
    id'application '
    id'com.github.johnrengelman.shadow 'version' 2.0.1 '
}
Gruppe 'com.example'
version '1.0-SNAPSHOT'
mainClassName = 'com.example.jda.Bot'
version '1.0'
sourceCompatibility = 1.8
Aufbewahrungsorte {
    jcenter ()
}
Abhängigkeiten {
    kompiliere 'net.dv8tion: JDA: 3.5.0_331'
    compile 'com.jagrosh: jda-utilities: 2.0'
}
compileJava.options.encoding = 'UTF-8'

Schritt 2

Jetzt verwenden wir den CommandClient von JDA-Utilities, um die Befehlsverarbeitung zu erledigen.

So sieht ein grundlegender Befehl aus:

öffentliche Klasse ModBot {
    public static void main (String [] args) löst LoginException aus {
        CommandClientBuilder commandClientBuilder = new CommandClientBuilder ();
        // Unser Präfix ist !!
        commandClientBuilder.setPrefix ("!!");
        // "Tippe !! help"
        commandClientBuilder.useDefaultGame ();
        commandClientBuilder.addCommand (neues HelloWorldCommand ());
        neuer JDABuilder (AccountType.BOT)
                .setToken ("Ihr-Token-geht-hier")
                .addEventListener (commandClientBuilder.build ())
                .buildAsync ();
    }
    öffentliche statische Klasse HelloWorldCommand erweitert Command {
        public HelloWorldCommand () {
            this.name = "helloworld";
            this.aliases = new String [] {"hw"};
            this.help = "sagt hallo";
        }
        @Override
        protected void execute (CommandEvent commandEvent) {
            commandEvent.reply ("Hallo Welt!");
        }
    }
}

GuildController

Alle Mod-Aktionen in JDA (z. B. Sperren, Treten, Hinzufügen oder Entfernen von Rollen, Stummschalten von Servern, Deaktivieren von Servern usw.) werden über die GuildController-Klasse ausgeführt.

Um den GuildController für eine Gilde abzurufen, rufen Sie die getController () -Methode auf.

RestActions

Alle JDA-Methoden, die mit der REST-API von discord interagieren, geben eine Instanz der RestAction-Klasse zurück.

Eine RestAction stellt eine Anforderung dar, die ausgeführt wird. Die Anforderung wird jedoch nur ausgeführt, wenn Sie queue (), complete () oder submit () für das RestAction-Objekt aufrufen. Wenn Sie keine dieser Methoden aufrufen, wird die Aktion niemals ausgeführt und Ihr Bot funktioniert nicht.

Verwenden Sie nach Möglichkeit die Methode queue () und deren Überlastungen, da sie den aktuellen Thread (nicht blockieren), damit andere Vorgänge nicht verlangsamt werden.

Kick

Führen Sie zunächst einen Kick-Befehl aus. Es wird ausgeführt als !! kick @Person, wobei Person die Person ist, die Sie treten möchten. Für diesen Befehl verwenden wir die Kick-Methoden Message # getMentionedMembers () und GuildController #.

So sieht unser Kick-Befehl aus:

@Override
protected void execute (CommandEvent commandEvent) {
    Guild guild = commandEvent.getGuild ();
    // Wenn wir keiner Gilde angehören, können wir niemanden treten
    if (guild == null) {
        commandEvent.reply ("Sie müssen diesen Befehl auf einem Server ausführen");
        Rückkehr;
    }
    Mitglied author = commandEvent.getMessage (). GetMember ();
    // Der Autor kann keine Leute treten
    if (! author.hasPermission (Permission.KICK_MEMBERS)) {
        commandEvent.reply ("Sie haben keine Erlaubnis, Leute zu treten!");
        Rückkehr;
    }
    Liste & lt; Mitglied & gt; specifiedMembers = commandEvent.getMessage (). getMentionedMembers ();
    if (specifiedMembers.isEmpty ()) {
        commandEvent.reply ("Sie müssen angeben, wen Sie treten möchten");
        Rückkehr;
    }
    guild.getController (). kick (namedMembers.get (0)). queue (success- & gt; {
        commandEvent.reply ("Erfolgreich gekickt" + specifiedMembers.get (0) .getUser (). getName ());
    }, error- & gt; {
        commandEvent.reply ("Kick nicht möglich" + specifiedMembers.get (0) .getUser (). getName () + ":" + error);
    });
}

Möglicherweise fragen Sie sich, wie die Syntax für x- & gt; {} lautet. Wenn Sie es nicht wissen, handelt es sich um Lambda-Ausdrücke, die den Schließungen von Javascript oder den Lambdas von Python ähneln.

Verbot

Die Art und Weise des Banns entspricht fast der Art und Weise, wie Sie treten, aber Sie müssen der GuildController-Methode # ban () ein zusätzliches Argument geben, nämlich wie weit die Nachrichten der gesperrten Person gelöscht werden.

Die Implementierung dieses Befehls wird Ihnen als Übung überlassen.

Softban

Ein Softban ist im Grunde ein Sperren und Aufheben des Sperrens, um die Nachrichten eines Benutzers zu stoßen und zu löschen. Lassen Sie uns jetzt einen implementieren, indem Sie den Befehl ban ändern:

guild.getController (). ban (member, 7 / * löscht alle Nachrichten aus dem Member der letzten Woche * /). queue (done- & gt; {
    guild.getController (). unban (member.getUser ()). queue (done2- & gt; {
        commandEvent.reply ("Softbanned" + member.getUser (). getName () + "#" + member.getUser (). getDiscriminator ());
    }, error- & gt; {
        commandEvent.reply ("Fehler beim Entbannen:" + Fehler);
    };
}, error- & gt; {
    commandEvent.reply ("Fehler beim Bannen:" + Fehler);
});

Stumm

Zum Stummschalten benötigen wir eine Stummschaltfunktion. Im Moment geben wir der Person nur die erste Rolle mit dem Namen "Muted", die wir finden:

Gildengilde = ...
GuildController controller = guild.getController ();
Liste & lt; Mitglied & gt; specifiedMembers = commandEvent.getMessage (). getMentionedMembers ();
if (specifiedMembers.isEmpty ()) {
    commandEvent.reply ("Sie müssen angeben, wen Sie treten möchten");
    Rückkehr;
}
Member toMute = specifiedMembers.get (0);
Rolle muteRole = guild.getRoles (). Stream (). Filter (r- & gt; r.getName (). Equals ("Muted")). FindFirst (). OrElse (null);
if (muteRole == null) {
    commandEvent.reply ("Keine Rolle mit dem Namen 'Muted' gefunden");
    Rückkehr;
}
controller.addSingleRoleToMember (toMute, muteRole) .queue (success- & gt; {
    commandEvent.reply ("Erfolgreich stumm geschaltet" + toMute.getUser (). getName ());
}, error- & gt; {
    commandEvent.reply ("Stummschalten nicht möglich" + toMute.getUser (). getName () + ":" + Fehler);
});

In diesem Beispiel werden der Java-Stream und optionale APIs verwendet

Auch hier bleibt die eigentliche Befehlsimplementierung als Übung für den Leser.

Tempmute

Wir werden jemanden für 1 Stunde stumm schalten und dann die Stummschaltung aufheben. Ändern wir unseren Stummschaltbefehl:

controller.addSingleRoleToMember (toMute, muteRole) .queue (success- & gt; {
    commandEvent.reply ("Erfolgreich stumm geschaltet" + toMute.getUser (). getName ());
    controller.removeSingleRoleFromMember (toMute, muteRole) .queueAfter (1, TimeUnit.HOURS, success2- & gt; {
        commandEvent.reply ("Nicht stummgeschaltet" + toMute.getUser (). getName ());
    }, error- & gt; {
        commandEvent.reply ("Stummschaltung kann nicht aufgehoben werden" + toMute.getUser (). getName () + ":" + Fehler);
    });
}, error- & gt; {
    commandEvent.reply ("Stummschalten nicht möglich" + toMute.getUser (). getName () + ":" + Fehler);
});

Dies verwendet die RestAction # queueAfter-Methode, was bedeutet, dass unsere ausstehenden Stummschaltungen verloren gehen, wenn der Bot neu gestartet wird. Um sie auch über Neustarts hinweg im Auge zu behalten, müssten sie in einer Datenbank gespeichert werden (keine Daten in JSON-Dateien speichern, die immer nach hinten losgehen), dies ist jedoch nicht Bestandteil dieses Lernprogramms.

Fluchwortfilter

Um unseren Filter zu erstellen, müssen wir unserem JDA-Objekt einen neuen Listener hinzufügen. Erstellen wir eine neue Klasse und erweitern ListenerAdapter:

public class CurseWorldFilter erweitert ListenerAdapter {
}

Lassen Sie uns nun die onGuildMessageReceived (GuildMessageReceivedEvent) -Methode überschreiben:

@Override
public void onGuildMessageReceived (GuildMessageReceivedEvent-Ereignis) {
}

Fügen wir auch eine Schimpfwortliste hinzu:

public class CurseWorldFilter erweitert ListenerAdapter {
    Private statische endgültige Liste & lt; Zeichenfolge & gt; CURSE_WORDS = Arrays.asList (
            "Einfügen", "Fluchen", "Wörter", "Hier", "Aber", "Nur", "In", "Klein", "Groß- / Kleinschreibung", "Bitte"
    );
    @Override
    public void onGuildMessageReceived (GuildMessageReceivedEvent-Ereignis) {
    }
}

Sehen wir uns nun an, ob es ein Schimpfwort gibt, und löschen Sie die Nachricht, falls vorhanden:

public class CurseWorldFilter erweitert ListenerAdapter {
    Private statische endgültige Liste & lt; Zeichenfolge & gt; CURSE_WORDS = Arrays.asList (
            "Einfügen", "Fluchen", "Wörter", "Hier", "Aber", "Nur", "In", "Klein", "Groß- / Kleinschreibung", "Bitte"
    );
    @Override
    public void onGuildMessageReceived (GuildMessageReceivedEvent-Ereignis) {
        // Den Rohinhalt abrufen (was der Benutzer eingegeben hat) und in Kleinbuchstaben konvertieren
        // Deshalb müssen wir in der obigen Liste Schimpfwörter in Kleinbuchstaben setzen
        String message = event.getMessage (). GetContentRaw (). ToLowerCase ();
        // Für jedes Schimpfwort in der Schimpfwortliste
        für (String curseWord: CURSE_WORDS) {
            // überprüfe, ob die Nachricht es enthält
            if (message.contains (curseWord)) {
                // Die Nachricht enthält ein Schimpfwort
                // Mal sehen, ob wir es löschen können
                // Wenn wir keine Berechtigung zum Löschen von Nachrichten haben, warnen wir und kehren zurück
                if (! event.getGuild (). getSelfMember (). hasPermission (event.getChannel (), Permission.MESSAGE_MANAGE)) {
                    System.out.println ("Keine Berechtigung zum Löschen von Nachrichten in #" + event.getChannel (). GetName ());
                    Rückkehr;
                }
                // versuche es zu löschen
                event.getMessage (). delete (). queue (ddone- & gt; {
                    // Wenn es gelöscht wurde, warnen Sie den Benutzer
                    event.getChannel (). sendMessage (event.getAuthor (). getAsMention () + ", das kann man nicht sagen!"). queue ();
                }, error- & gt; {
                    // Wenn wir einen Fehler beim Löschen haben, drucken Sie ihn aus
                    System.out.println ("Fehler beim Löschen der Nachricht mit Schimpfwort");
                    error.printStackTrace ();
                });
                Rückkehr;
            }
        }
    }
}

Wenn wir unseren Bot jetzt ausführen, werden wir feststellen, dass er Schimpfwörter vollständig ignoriert. Das liegt daran, dass wir den Hörer nicht registriert haben. Kehren wir nun zu unserer Hauptklasse zurück und ändern Sie .addEventListener (commandClientBuilder.build ()) in .addEventListener (commandClientBuilder.build (), new CurseWorldFilter ()), damit unser Listener registriert wird.

Führen Sie den Bot erneut aus, und Sie werden feststellen, dass er jetzt Schimpfwörter erkennt und diese löscht.