Kannst du mir ein paar typische Dinge nennen, die Plugins inkompatibel machen? Wie kann man sowas, aus deiner Sicht, am besten vermeiden und was für Dinge musstest du bisher ändern? Würde mich interessieren, damit ich das in Zukunft direkt mit beachten kann. Selbst habe ich noch nicht so viele Plugins ausprobiert und hatte daher auch noch nie Probleme.
Ich beantworte das mal.
- Namenskollisionen bzw. unachtsame Nutzung globaler Variablen.
Das lässt sich leicht durch strict-mode und eine IIFE um den Code lösen (wobei ich da stattdessen gern einen try/catch-block verwende, da MV etwas Hilfe beim Anzeigen von Fehlern beim Pluginstart braucht).
Wenn es eine JS-API gibt, dann sollte diese durch eine einzelne globale Variable mit dem Namen des Plugins erreichbar sein.
- intransparentes Ueberschreiben von Methoden bzw. die Aenderung von Aufrufsignaturen.
Also wenn einfach eine neue Version der Funktion eingefuegt wird und es keinen return old.apply(this, arguments);-Aufruf gibt. Ich persoenlich schreibe das auch dann so rein, wenn es weder parameter noch einen Rueckgabewert gibt, da ich nicht weiss, ob jemand anderes an der Stelle diese Regel verletzt.
- Aenderung von Objekten aus der Spielengine selbst.
Dies fuehrt oft zu Namenskollisionen. Man kann den Namen der Properties den Namen des Plugins voranstellen, aber ich benutze stattdessen normalerweise eine WeakMap, da ich nicht moechte, das andere an der Stelle die API meines Plugins umgehen.
(Fuer CustomTraits wuerde ich ein concat auf das Ergebnis von Game_Actor.prototype.currentClass machen, statt das Datenarray zu aendern. Das ist erstmal sauberer und es kann ja sein, dass in den urspruenglichen Daten absichtlich Duplikate vorkommen.)
- keine API / nicht-modifizierbare Hooks
Die oeffentlichen Funktionen des Plugins und solche, die nuetzlich sein koennten, sollten anderen Plugins zur Verfuegung stehen. Fuer die Hooks schreibe ich normalerweise sowas hier:
const api = window[MY_PLUGIN_NAME] = {
version: {
featureLevel: 2,
patchLevel: 0,
},
/** @since 1.1.0 */
oldA_ClassAMethod = A_Class.prototype.aMethod,
...(A_Class.prototype.aMethod = function () { return api.newA_ClassAMethod.apply(this, arguments); }, {}),
newA_ClassAMethod(some, parameters) {
// Your code here.
const result = api.oldA_ClassAMethod.apply(this, arguments);
// Your code here.
return result;
},
};
Alles anzeigen
Sieht etwas nervig aus, aber dadurch koennen sich andere Plugins dann vor oder nach diesem Aufruf einklinken oder ihn deaktivieren, ohne dass etwas an meinem Plugin geaendert werden muss. (gut fuer Updates, auch die Versionierung)
- Aenderungen am Aufrufkontext.
Wenn man das Verhalten von Szenen anpasst, muss man z.B. auf Scene_Boot achten, da waerend dieser Szene die Spieldaten noch nicht initialisiert sind. Es kann auch bei neuen Kampfmodi solche Probleme geben, falls andere Plugins eine bestimmte Phasenreihenfolge voraussetzen.
Man kann nicht immer alle Probleme vermeiden, aber meistens geht's ziemlich gut.
(Das ist kein sauberes JSDoc, aber ich glaube das kriegt man bzgl. RPG Maker auch kaum 100% korrekt hin waerend der Quellcode noch lesbar ist.)