Artikel

Ein verwaistes Plugin forken — zwei Zeilen waren die Ursache

Ein Plugin, das seit Jahren niemand mehr pflegt, startet auf der neuen Minecraft-Version nicht. Die Ursache lag in der Versionserkennung — und der zweite Fehler kam erst zum Vorschein, als der erste behoben war.

BlackZackBlackzack

1007 Wörter · 5 Min. Lesezeit

  • minecraft
  • plugin
  • eigenbau

Von den Plugins, die den Versionssprung nicht überlebt hatten, war eines besonders ärgerlich: Es liefert die Formulare, über die Bedrock-Spieler mit Menüs umgehen. Ohne es funktionieren die Dialoge von einem Dutzend Figuren im Spiel nicht.

Das Projekt ist verwaist. Die letzte Aktivität liegt Jahre zurück. Es gibt eine gepflegte Kopie im Netz, aber auch die steht auf derselben Fassung.

Also selbst forken. Was ich dabei gelernt habe, gilt für viele alte Plugins.

Warum das gefahrlos war

Bevor ich anfange, an fremdem Code zu arbeiten, will ich wissen, wie tief das Problem sitzt. Die Frage ist immer dieselbe: Benutzt das Plugin interne Serverklassen, oder arbeitet es mit der öffentlichen Schnittstelle?

Interne Klassen ändern sich mit jeder Minecraft-Version. Ein Plugin, das darauf aufbaut, ist bei einem Versionssprung ein Umbauprojekt.

Hier war die Antwort erfreulich: Kein einziger der Versionsadapter benutzt interne Klassen. Der neueste überschreibt genau eine Methode. Das Plugin lief schon auf der Vorversion über eine Suche nach dem „nächstbesten" Adapter.

Damit war klar: Das Problem liegt nicht in der Anpassung an die neue Version, sondern in der Erkennung, welche Version überhaupt läuft.

Die erste Ursache: eine Revision ohne Zahl

Minecraft-Serverfassungen tragen eine Versionsangabe, die früher immer nach demselben Muster aufgebaut war — Hauptversion, Nebenversion, Revision mit einer Zahl darin.

Seit die Versionsnummerierung auf ein datumsbasiertes Schema gewechselt hat, sieht die Revision anders aus: Sie enthält keine Zahl mehr. Der Code, der sie in eine Zahl umwandelt, brach ab.

Die Behebung: Eine Revision ohne Zahl zählt als erste Revision. Das ist genau die Bedeutung, die sie hat.

Die zweite Ursache: die Hauptversion ist nicht mehr 1

Nachdem der erste Fehler behoben war, kam der nächste zum Vorschein — und das ist ein Muster, das ich bei solchen Arbeiten oft sehe: Fehler stapeln sich, und man sieht immer nur den obersten.

Die Zuordnung von Version zu Adapter ging davon aus, dass die Hauptversion immer 1 ist und nur die Nebenversion zählt. Bei einer Hauptversion, die nicht 1 ist, kam „nicht unterstützt" zurück.

Behebung: Eine unbekannt hohe Hauptversion wählt den neuesten Adapter — dieselbe Schlussfolgerung, die die Methode für zu neue Nebenversionen ohnehin zieht.

Die dritte Ursache: ein Paket, das es nicht mehr gibt

Und noch einer, der erst nach den ersten beiden sichtbar wurde. Diesmal ein Absturz mit einem Zugriff auf ein Feld, das es nicht gibt.

Der Code las den Paketnamen einer Serverklasse und nahm daraus ein bestimmtes Segment, um die Version abzuleiten. Das war jahrelang üblich, weil diese Klassen in versionierten Paketen lagen.

Die aktuellen Serverfassungen haben das versionierte Paket abgeschafft. Der Name hat ein Segment weniger, der Zugriff läuft ins Leere.

Behebung: Rückfall auf die reguläre Versionsangabe. Und eine Erkenntnis, die weit über dieses Plugin hinausgeht: Dieselbe Falle trifft jedes alte Plugin, das den Paketnamen zerlegt. Das ist ein gutes Erkennungsmerkmal bei ähnlichen Abstürzen.

Infobox

Beim Bauen selbst gab es eine eigene kleine Odyssee: Das Projekt lässt sich nur mit einer bestimmten Java-Fassung bauen. Mit einer neueren stolpert die Annotationsverarbeitung, mit einer noch neueren das mitgelieferte Bauwerkzeug. Die Lösung ist ein Container mit genau der passenden Fassung — statt die Bauumgebung des eigenen Rechners umzustellen. Für alte Projekte ist das inzwischen mein Standardvorgehen.

Was den Fork rechtfertigt

Ich baue ungern Forks. Sie sind eine dauerhafte Verpflichtung: Jede künftige Änderung muss ich selbst machen.

Hier waren die Gründe eindeutig:

  • Das Original ist verwaist. Es gibt niemanden, dem man einen Verbesserungsvorschlag schicken könnte.
  • Die Änderung ist minimal. Drei Stellen in der Versionserkennung, keine einzige in der Fachlichkeit.
  • Die Alternative wäre ein Ersatz. Ein vergleichbares Plugin gibt es nicht, und ein Eigenbau wäre ein Vielfaches an Arbeit.
  • Es gibt Tests. Ich habe die Versionserkennung mit den neuen Versionsformaten geprüft — inklusive einer erfundenen zukünftigen Version, um zu sehen, ob die Logik weiter trägt.

Der letzte Punkt ist der, der aus einem Notbehelf eine wartbare Sache macht. Ein Fork ohne Test ist ein Patch, den man beim nächsten Versionssprung neu erraten muss.

Was ein Fork an Pflege bedeutet

Ein Fork ist eine dauerhafte Verpflichtung, und ich habe mir aufgeschrieben, was sie umfasst — damit ich sie nicht unterschätze.

Bei jedem Minecraft-Versionssprung prüfen, ob die Anpassungen noch greifen. Bei einem Plugin, dessen Problem in der Versionserkennung lag, ist die Wahrscheinlichkeit hoch, dass genau dort wieder etwas ansteht.

Sicherheitsmeldungen selbst verfolgen. Es gibt niemanden mehr, der eine Behebung ausliefert.

Den Bauvorgang lauffähig halten. Ein Projekt, das nur mit einer bestimmten alten Java-Fassung baut, braucht diese Umgebung dauerhaft. Ein Container mit fester Fassung ist dafür die richtige Antwort — er macht die Abhängigkeit ausdrücklich, statt sie an den eigenen Rechner zu binden.

Die Änderungen dokumentiert halten. Bei mir liegt neben dem Fork eine Datei mit drei Absätzen: was geändert wurde, warum, und wie man es prüft.

Diese vier Punkte sind der Preis. Sie sind vertretbar, wenn die Alternative „das Plugin fällt weg" heißt — und sie sind zu teuer, wenn es einen gepflegten Ersatz gibt.

Der Test, der aus dem Fork ein Projekt macht

Der Unterschied zwischen einem Patch und einem wartbaren Fork ist bei mir ein einziger Test.

@Test
void erkenntDatumsbasierteVersionen() {
  assertEquals(NEUESTER, adapterFuer("26_1_Rstable"));
  assertEquals(NEUESTER, adapterFuer("26_2_Rstable"));
  assertEquals(NEUESTER, adapterFuer("27_1_R1"));   // erfundene Zukunft
}

Die dritte Zeile ist die wichtigste. Sie prüft eine Version, die es nicht gibt — und beantwortet damit die Frage, ob meine Anpassung auch beim nächsten Sprung noch trägt oder nur zufällig für die aktuelle Fassung passt.

Ohne diesen Test hätte ich beim nächsten Versionssprung wieder von vorne angefangen zu raten. Mit ihm dauert die Prüfung eine Minute: Test laufen lassen, und wenn er grün ist, ist die Erkennung in Ordnung.

Was ich mitnehme

Erst prüfen, wie tief das Problem sitzt. Ein Plugin, das nur die öffentliche Schnittstelle benutzt, ist fast immer rettbar. Eines mit internen Zugriffen ist ein anderes Projekt.

Fehler stapeln sich. Nach der ersten Behebung ist man nicht fertig, sondern sieht die nächste Ebene. Das ist kein Rückschlag, sondern Fortschritt — man muss nur damit rechnen.

Versionserkennung ist eine erstaunlich häufige Fehlerquelle. Nicht die Fachlichkeit bricht, sondern das Herausfinden, wo man überhaupt läuft. Bei den nächsten alten Plugins habe ich genau dort zuerst gesucht — und wurde zweimal fündig.