Dokumentation/CommandFramework.md
D4rkr34lm 611293a14a Added new Paragraph
-Type Matches auf eigene Typen ermöglichen
2023-08-19 11:59:33 +02:00

4.1 KiB

Steamwar - Command Framework

Inhalt

Erstellung eines neuen Commands

Um einen neuen Command zu erstellen musst du eine neue Klasse erstellen, die von der Klasse SWCommand erbt. Danach musst du einen Konstruktor ohne Argumente schreiben. Nun musst du noch den super-Constructor aufrufen. Diesem musst du nun zunächst den Namen des Commands mitgeben.Danach kanst du noch belibig viele weitere Argumente angeben. Diese sind Aliasse für den Command.

public class NewCommand extends SWCommand {
    
    public NewCommand() {
        super("Name", "Aliase"...);
    }
}

Einem Command Funktionalität hinzufügen

Warnung: Um den folgenden Teil zu verstehen, ist es notwendig die Grundlagen der Funktionalen Programmierung zu verstehen
Damit der Command Funktionalität hat musst du Patterns defienieren. Ein solches Pattern erstellst du, indem du eine Methode erstellst und dies mit @Register anotierst. Das erste Argument dieser Methode muss vom Typ CommandSender sein. Alle folgenden Argumente werden dan für das Pattern match verwendet. Das Patternmatching funktioniert so, dass wenn ein Command aufgerufen wird, das Framework verucht die Argumente des Commands auf die Argumente einer Registrirten Methode zu matchen. Geht dies, so wird die Methode aufgerufen. Sollte der Patternmatch fehlschlagen, wird die default Help-Message gesendet. Um besser zu verstehen, wie solch ein Patternmatch abläuft, wollen wir uns folgendes Beispiel angucken:

public class TestCommand extends SWCommand {

    public TestCommand() {
        super("test","dev");
    }

    @Register
    public void pattern1(CommandSender sender, int argument) {
        System.out.println(argument);
    }

    @Register
    public void pattern2(CommandSender sender, boolean argument) {
        System.out.println(argument);
    }
}

Betrachten wir nun folgende Eingabe eines Users /test true da true ein boolean-Wert ist wird das Framework entry2 aufrufen, da diese Methode genau ein boolean-Argument akzeptiert. Betrachten wir nun einen weiteren Aufruf: /test 12. Bei diesem Aufruf wurde ein Argument vom Typ int angegeben. Also wir entry1 aufgerufen.

Type Matches auf eigene Typen ermöglichen

Um Matchings auf einen eigenen Typen zu ermöglichen, ist es zuerst notwendig einen TypeMapper zu schreiben. Hierzu ist es notwendig das TypeMapper-Interface zu implementieren. Bei dieser Implementation ist es notwendig die map-Methode zu implementieren. In dieser Methode definierst du, wie der Command Input auf den gewünschten Typ gemappt wird. Zusätzlich musst du auch noch die tabCompletes-Methode implementiern. In dieser bestimmst du, welche TabCompleations dem Nutzer, abhängig vom Momentanen und vorheriegen Inputs vorgeschlagen werden. Schauen wir uns dies nun einmal an einem Beispiel an:

public class BooleanMapper extends TypeMapper<Boolean>{
       
    @Override
    public Boolean map(Object sender, PreviousArguments previousArguments, String s) {
        if (s.equalsIgnoreCase("true")) return true;
        if (s.equalsIgnoreCase("false")) return false;
        return null;
    }

    @Override
    public List<String> tabCompletes(Object sender, PreviousArguments previousArguments, String s) {
        return Arrays.asList("true", "false");
    }
}

Nachdem wir nun den Mapper defeniert haben ist es noch notwendig den Mapper zu registrieren. Hierzu erstellst du eine Methode, die eine Instanz des Mappers zurück gibt. Diese Methode annotierst du dan noch mit @ClassMapper(value=Type.class, local=true). Das Atribut value muss hierbei auf die Klasse des zu matchenden Typen gesetzt werden. Weiterhin kanst du mit local defenieren, ob der Mapper nur innerhalb der Klasse, oder Global gelten soll. Der Code zu dem vorheriegen Beispiel sähe zum Beispiel so aus:

@ClassMapper(value=Boolean.class, local=false)
public TypeMapper<Boolean> booleanMapper(){
    return new BooleanMapper();
}