Plugin und Java

  • Hallo @red51,


    Ich hab in der Roadmap gesehen, dass du Plugin API Java Integration eingefügt hast.


    Darf ich davon ausgehen, dass ich auch zukünftig ganz Normal Plugins in Java schreiben kann oder muss ich C# lernen oder kann man dann mit beiden schreiben?


    Wenn man mit beiden schreiben kann, welche Sprache ist dann besser?


    Gibt es irgendwelche Änderungen beim Programmieren zu beachten oder wird versucht die API 1:1 zu übertragen?

  • Hehe, sehr aufmerksam beobachtet ;)


    Tatsächlich war die Formulierung in der Roadmap etwas irreführend... ich habe das jetzt abgeändert, damit sollte es eigentlich keine Unklarheiten mehr geben ^^


    Grundsätzlich wird Java weiterhin die Programmiersprache für Plugins bleiben. Ggf. werden wir langfristig noch JavaScript hinzufügen, aber das steht noch nicht ganz fest. Andere Sprachen wie C# werden leider nicht unterstützt (die neue Version des Spiels wird zwar überwiegend in C# geschrieben, aber der fertige Code wird durch IL2CPP in C++ umgewandelt)


    Die neue Plugin API wird in weiten Teilen identisch zur bisherigen API bleiben, es wird aber aus technischen Gründen ein paar kleinere notwendige Änderungen geben (zB wird der Zugriff auf die Server und World Klassen statisch sein [d.h. z.B. nicht mehr getServer().getPlayer(); sondern direkt Server.getPlayer();], Events sind nur noch innerhalb der Eventfunktion gültig [d.h. Events können leider nicht in Listen gespeichert oder an andere Threads übergeben werden - in dem Fall müsste man sich die Daten aus einem Event vorher selber rauskopieren], EventMethod.Threaded wird entfernt [ich glaube das wurde eh nicht so oft verwendet, und ist in den meisten Fällen auch gar nicht nötig] und noch ein paar kleinere Syntaxänderungen). D.h. Plugins können zwar leider nicht 1:1 übernommen werden, doch die nötigen Anpassungen durch den Pluginersteller werden insgesamt überschaubar bleiben. Etwas größere Änderungen *könnten* lediglich bei der GUI stattfinden, da kann ich leider noch nicht ganz so viel zu sagen... auch kann es sein, dass sich der Workflow für Custom Items und so etwas ändert. Auch bei der WorldDatabase kann es sein, dass es etwas Probleme gibt.


    Ich werde demnächst noch einen Thread erstellen, der die Änderungen an der API etwas genauer beleuchtet (zumindest die Änderungen, die nach jetzigem Stand feststehen). Generell spricht nichts dagegen, weiterhin Plugins zu schreiben, denn die später notwendigen Anpassungen sollten in den meisten Fällen recht zügig vonstatten gehen (lediglich in puncto GUI wäre es vll ratsam, sich vorerst aufs Wesentliche zu beschränken).


    Also kurz gefasst könnte man folgendes schonmal berücksichtigen:

    • Events nur innerhalb der Event Funktion nutzen (wenn sie getriggert werden), niemals in eine Liste reinschreiben oder an einen anderen Thread übergeben. An Funktionen übergeben ist hingegen ok, sofern diese sich an die selben Regeln hält
    • EventMethod.Threaded sollte nicht mehr verwendet werden, da es wie gesagt rausfliegt. Meistens ist es eh nicht so sinnvoll, diesen Modus zu verwenden, da die meisten Events ohnehin aus verschiedenen Threads getriggert werden
    • Man sollte vermeiden, zu viele Threads zu erzeugen. In den meisten Fällen sind Threads ohnehin nicht nötig, da der Server die API-Aufrufe bereits aus verschiedenen Threads tätigt. Wenn man wirklich eigene Threads braucht, sollte man vorsichtig sein wenn API Funktionen aus diesen Threads aufgerufen werden: Jeder erstmalige Aufruf einer API Funktion aus einem neuen Thread sorgt für viel Overhead! Wenn man nun zB einen Executer bzw. Scheduler verwendet, der unter der Haube immer wieder einen neuen Thread spawnt, kann das schon sehr ins Gewicht fallen
    • Evtl. wäre es ratsam, die WorldDatabase erstmal nicht zu benutzen. Hier kann es sein, dass es einige Änderungen gibt (muss aber nicht). Das Problem ist, dass die Datenbank bereits vom Spiel gelocked wird, und der Zugriff über Java dann nicht mehr so einfach ist. Normale SQLite Datenbanken (also von Plugins erstellte Datenbanken) sind aber kein Problem
    • Es wird vom Spiel generell keinen MySQL Support mehr geben. Dadurch werden möglicherweise auch die MySQL Funktionen aus der API entfallen. In Java gibts aber natürlich andere Lösungen dafür, d.h. wenn ein Plugin unbedingt MySQL Zugriff braucht, muss es notfalls selber den JDBC Treiber als Lib laden
  • Hey
    Im letzten Abschnitt schreibst du das es generell keinen msql Support mehr geben wird. Ist dies jetzt nur auf die Plugin bezogen ( so würde ich es jetzt verstehen) oder auch generell für den mp Server ? :?:


    Ich freue much, dass es jetzt eine Antwort darauf gibt, wie es mit den Plugins weiter geht und das die alten noch aktuellen wohl Recht schnell angepasst sind :thumbup:

  • Im letzten Abschnitt schreibst du das es generell keinen msql Support mehr geben wird. Ist dies jetzt nur auf die Plugin bezogen ( so würde ich es jetzt verstehen) oder auch generell für den mp Server ?

    Das gilt generell für den MP Server. In der neuen Version haben wir eine wesentlich schlankere SQLite Implementation, die keinen unnötigen Overhead mit sich bringt und spürbar schneller arbeitet als die alte Java Integration - insgesamt sollte das den Geschwindigkeitsvorteil von MySQL schon weitestgehend aufwiegen können. Optional wird es voraussichtlich auch die Möglichkeit geben, Memory-Datenbanken zu erstellen (daran arbeiten wir noch) - diese dürften noch schneller als MySQL sein. Dadurch, dass wir uns nur auf SQLite konzentrieren, können wir auch direkt ein paar Zusatzfeatures bieten wie zB automatische Welt-Backups.


    Wir halten uns die Option mit MySQL aber offen - wenn wir feststellen, dass es wider Erwarten doch zu Performanceproblemen kommt, werden wir eine MySQL Integration hinzufügen. Aber wie gesagt, es sieht momentan stark danach aus, dass die neue SQLite Integration schneller als die alte Java MySQL Integration sein wird ;)

  • Events nur innerhalb der Event Funktion nutzen (wenn sie getriggert werden), niemals in eine Liste reinschreiben oder an einen anderen Thread übergeben. An Funktionen übergeben ist hingegen ok, sofern diese sich an die selben Regeln hält

    Was meist du damit? Kannst du mir ein bespiel Zeigen, wie man es nicht machen soll und wie man es machen soll?


    "Niemals in eine Liste reinschreiben": Soll das heißen, ich kann für AktiveSign keine Schilder-Liste erstellen und sie mit den Events abfragen?

  • Das bedeutet, dass das Event Objekt nach Aufruf der Event Funktion ungültig wird. Hier ist ein Beispiel:

    Java
    @EventMethod
    public void onChatMessage(PlayerChatEvent event){
    //Hier überall ist das event gültig
    String msg = event.getChatMessage();
    event.setChatMessage("[UselessPrefix] " + msg);
    //AB HIER IST EVENT UNGÜLTIG
    }


    Innerhalb der "onChatMessage()" Funktion kannst du mit dem Event machen was du willst. Nachdem die Event-Funktion aber abgearbeitet wurde (also ab Zeile 7) verliert das Event seine Gültigkeit.


    Du kannst natürlich weiterhin andere Sub-Funktionen aufrufen, zB sowas ist absolut ok:


    Was aber nicht erlaubt ist, ist Events irgendwo zwischenzuspeichern und später irgendwie nochmal zu verwenden. Folgendes ist zB verboten:


    Was aber hingegen wieder ok wäre, wenn du die eigentlichen Daten des Events zwischenspeicherst. Statt also im obigen Beispiel das "PlayerChatEvent" zwischenzuspeichern, wäre es besser, die eigentliche Chatnachricht (oder was auch immer) zu speichern. Beispiel:


    Was auch geht: Eine eigene Klasse erstellen die alle Daten des Events entgegennimmt:



    Generell wird es in der neuen API so sein, dass die Events auf Java Seite nur noch eine "leere Hülle" sind mit nur einer Variablen - nämlich einen Pointer auf die Memory-Adresse des nativen Events (genau genommen gibt es in Java keine Pointer, daher wird einfach die Memory-Adresse als 64 bit Wert gespeichert - es handelt sich also vielmehr um einen Handle). Bei Funktionsaufrufen wie zB "getChatMessage()" wird eine native Funktion aufgerufen und der Pointer (bzw. die gespeicherte Memory-Adresse bzw. der Handle) des Events übergeben. Auf nativer Seite wird das Event aus dieser Memory-Adresse ausgelesen und dann der gewünschte Funktionswert zurückgegeben (in dem Fall die Chat-Nachricht).
    Nachdem aber alle Event-Funktionen durchlaufen sind, wird das native Event gelöscht und der verwendete Speicher freigegeben - d.h. das Java Event würde nun auf eine ungültige Memory-Adresse verweisen (und ein Zugriff darauf würde in den allermeisten Fällen das Spiel crashen). Um das zu verhindern, wird nach Ende des Event-Aufrufs die Memory-Adresse bzw. der Handle auf 0 gesetzt und bei jedem weiteren Funktionsaufruf stattdessen eine Exception geworfen.


    Insgesamt sieht das ganze in etwa so aus:


    • Natives PlayerChatEvent wird erstellt und die Memory-Adresse, an der es sich befindet, ausgelesen
    • TriggerEvent(PlayerChatEvent) wird aufgerufen - eine zentrale Funktion, die alle Event Listener benachrichtigt
      • Ein Java Objekt "PlayerChatEvent" wird erstellt und der Pointer bzw. der Handle übergeben
      • Für jedes einzelne Plugin wird nun die registrierte Fkt. für das Chat-Event aufgerufen, in unserem Beispiel wäre das "OnChatMessage(PlayerChatEvent)" - bis hier hin ist alles cool
      • Wenn eine Event-Funktion von einem Plugin aufgerufen wird (zB "getChatMessage()"), wird auf nativer Seite das native Event an der entsprechenden Memory-Adresse ausgelesen und der gewünschte Wert zurückgegeben - hier also die eigentliche Chat-Nachricht als String
    • Nachdem alle Plugin-Funktionen aufgerufen wurden, werden die Pointer bzw. die gespeicherten Memory-Adressen in den Java-Events auf 0 gesetzt (ab sofort kann keine Event-Funktion wie "getChatMessage() mehr aufgerufen werden)
    • Die geänderten Daten im nativen PlayerChatEvent werden vom Spiel weiterverwendet (wie zB die möglicherweise geänderte Chat-Nachricht) und das native Event wird gelöscht - der Memory an der Stelle wird für andere Dinge freigegeben


    Ich hoffe, das war einigermaßen verständlich ;) In den meisten Fällen sollte diese Änderung eigentlich keine größere Einschränkung bedeuten - denn auch schon in Java wäre sowas in manchen Fällen etwas gefährlich gewesen (bspw. wenn ein Event-Objekt gespeichert wird, und dann ne halbe Stunde später der Player dahinter oder so ausgelesen worden wäre - der möglicherweise gar nicht mehr auf dem Server ist).
    Es dürfen wie gesagt alle Daten eines Events in Listen gespeichert werden (im Zweifelsfall kann man auch eine eigene Klasse erstellen die die einzelnen Event-Daten aufnimmt), es darf nur das Event-Objekt selber nicht in eine Liste gepackt werden.

Participate now!

Don’t have an account yet? Create a new account now and be part of our community!