Artikel

Alten Plugins die Version vorlügen

Zwei Techniken für Plugins, die es nicht mehr gibt: den Versionsabruf abfangen und interne Klassennamen umschreiben. Wo die Grenzen liegen — und wann man es lieber lässt.

BlackZackBlackzack

917 Wörter · 5 Min. Lesezeit

  • minecraft
  • plugin
  • bytecode

Die Minecraft-Versionsnummerierung ist von einem Schema mit führender Eins auf ein datumsbasiertes gewechselt. Für Spieler ist das eine Kosmetik. Für Plugins, die die Versionsnummer auswerten, ist es ein Bruch.

Sehr viele alte Plugins zerlegen die Versionsangabe und schließen aus der zweiten Zahl auf das Alter des Servers. Bei einer Hauptversion, die nicht mehr Eins ist, kommen dabei absurde Ergebnisse heraus — typischerweise „sehr alter Server", woraufhin das Plugin nach internen Klassen sucht, die es auf modernen Fassungen nicht gibt.

Für zwei Plugins, die ich behalten wollte und für die es keine neuen Fassungen gibt, habe ich mir zwei Techniken erarbeitet.

Technik 1: Den Versionsabruf abfangen

Viele Plugins benutzen dieselbe verbreitete Hilfsbibliothek, um Versionen zu erkennen. Sie ruft eine Methode des Servers auf, die die Version als Text liefert, und wertet diesen Text aus.

Der Eingriff: Diesen Aufruf abfangen und das Ergebnis ersetzen. Wenn der Text zur neuen Ära passt, wird eine Kennung der letzten alten Version untergeschoben.

Aufruf: Server.getVersion()  →  "26.2-R0.1-SNAPSHOT"
Abfangen: passt auf die neue Ära?
   ja  → "1.21.4-R0.1-SNAPSHOT" zurückgeben
   nein → Original zurückgeben

Das klingt nach einem groben Hack und ist erstaunlich sicher, wenn eine Bedingung erfüllt ist: Das Plugin darf die Version nur zur Fallunterscheidung benutzen, nicht für echte Zugriffe auf interne Klassen. Bei einem Plugin, das ohnehin nur die öffentliche Schnittstelle benutzt, ist die Versionserkennung reine Selbstbeschränkung.

Zwei praktische Hinweise:

Es können mehrere Aufrufstellen sein, auch in inneren Klassen. Wer nur eine erwischt, wundert sich, warum es weiterhin bricht.

Die Hilfsbibliothek liegt manchmal umbenannt in einem anderen Plugin. Sie wird beim Bauen in einen eigenen Namensraum verschoben — und ist dann als eigenständige Datei ersetzbar, ohne das Hauptplugin anzufassen.

Technik 2: Interne Klassennamen umschreiben

Der schwerere Fall. Ein Plugin greift direkt auf interne Serverklassen zu und importiert deren alte Namen. Auf modernen Fassungen heißen sie anders.

Der Eingriff besteht darin, die Namen in der Programmdatei zu ersetzen — in der Konstantentabelle, in der alle Zeichenketten und Klassenverweise stehen.

Wichtig dabei:

Die Zielnamen vorher überprüfen, gegen die tatsächliche Serverdatei. Nicht raten, nicht aus einer Tabelle im Internet übernehmen. Ich habe für jede Umbenennung nachgesehen, ob die Zielklasse in der Serverfassung existiert.

Auf Byte-Ebene arbeiten ist zuverlässiger als über Bibliotheken. Werkzeuge zum Umschreiben lassen Fragmente in Signaturen und Zeichenketten stehen. Ein direkter Durchgang durch die Konstantentabelle erwischt alles — man muss nur die Längenangaben mit anpassen, weil die neuen Namen andere Längen haben.

Reste alter Codepfade sind egal. In einem der Plugins gab es eine ganze Variante für sehr alte Serverfassungen. Sie wird auf modernen nie geladen, also müssen ihre Verweise nicht stimmen.

Warnung

Die Grenze dieser Technik ist klar benennbar: Sie hilft nur, wenn sich Namen geändert haben — nicht, wenn sich Verhalten geändert hat. Wenn eine interne Klasse heute andere Felder oder andere Signaturen hat, reicht Umbenennen nicht. Dann bekommt man einen Fehler beim Zugriff statt beim Laden, und der ist deutlich unangenehmer, weil er mitten im Betrieb auftritt.

Wann ich es lasse

Ich habe eine kurze Liste von Bedingungen, unter denen ich so etwas nicht mache:

Wenn das Plugin sicherheitsrelevant ist. Ein gepatchtes Plugin, das Rechte prüft, ist ein Risiko, das ich nicht eingehe.

Wenn es Daten schreibt, die ich nicht selbst lesen kann. Wenn der Patch irgendwo subtil falsch ist, merkt man es an beschädigten Daten — und dann ist es zu spät.

Wenn es einen Nachfolger gibt. Zwei Plugins in meinem Bestand habe ich nicht gepatcht, sondern ersetzt. Ein gepflegtes Plugin, das achtzig Prozent kann, schlägt ein gepatchtes, das hundert kann.

Wenn ich den Zweck nicht mehr belegen kann. Wenn niemand mehr sagen kann, warum dieses Plugin da ist, ist die Antwort nicht „patchen", sondern „entfernen".

Wie ich einen Patch dokumentiere

Ein gepatchtes Plugin ohne Dokumentation ist eine Zeitbombe für das eigene zukünftige Ich. Deshalb liegt bei mir neben jeder angepassten Datei eine Notiz mit fünf Angaben.

Was war das Problem? Mit dem wörtlichen Fehlertext, damit man es beim nächsten Mal wiederfindet.

Was wurde geändert? Welche Klasse, welche Methode, welcher Wert.

Warum genau so? Die Begründung, nicht nur die Handlung.

Wie wurde geprüft? Was habe ich gemacht, um zu sehen, dass es wirkt?

Wo liegt das Original? Der Rückweg.

Dazu bleibt die unveränderte Fassung mit einem Zusatz im Dateinamen liegen. Ein Patch ohne Original ist unumkehrbar, und das ist bei einem Eingriff in fremden Code die falsche Ausgangslage.

Der Zeitpunkt, an dem ein Patch endet

Ich habe mir angewöhnt, jeden Patch mit einem Ablaufdatum zu versehen — nicht technisch, sondern als Vermerk.

„Gepatcht am 14.08. Prüfen, ob es beim nächsten Versionssprung einen Nachfolger gibt. Wenn nicht: ersetzen oder streichen."

Ohne diesen Vermerk wird aus einer Zwischenlösung ein Dauerzustand. Und Dauerzustände dieser Art sammeln sich: Nach drei Jahren betreibt man ein System mit fünf gepatchten Fremdkomponenten, deren Anpassungen niemand mehr nachvollziehen kann.

Meine Erfahrung nach diesem Sommer: Ein Patch ist gerechtfertigt, um Zeit zu gewinnen. Er ist nicht gerechtfertigt als Ersatz für eine Entscheidung. Und der Unterschied zeigt sich daran, ob man sagen kann, wann man ihn wieder loswird.

Warum ich das trotzdem aufschreibe

Nicht, weil ich das für einen guten Zustand halte. Ein gepatchtes Plugin ist eine dauerhafte Verpflichtung, und beim nächsten Sprung geht es von vorne los.

Sondern weil es eine Zwischenlösung ist, die einen Server am Laufen hält, während man den Ersatz baut. Genau in dieser Rolle ist sie wertvoll — und in genau dieser Rolle wird sie gefährlich, wenn man den Ersatz dann nicht baut.

Alle Patcher, Skripte und Sicherungskopien liegen bei mir mit Datum und Begründung nebeneinander. Damit ich beim nächsten Mal weiß, was ich damals getan habe — und damit jemand anderes es rückgängig machen kann.