OMSI Plugin Framework IV
Das OMSI Plugin Framework
Allgemeines
In diesem Kapitel werde ich den Aufbau und die Arbeitsweise des Frameworks detailliert beschreiben. Vielleicht hast Du dich die ganze Zeit schon gefragt, wozu so ein Framework-Dingens überhaupt gut ist. Ganz allgemein gesagt, soll Dich ein Framework von immer wiederkehrenden Standardaufgaben entlasten und Dir eine einheitliche Schnittstelle bieten, mit der Du bestimmte Aufgaben erledigen kannst. Im Falle des OMSI Plugin Frameworks übernimmt es auch noch einen etwas schwierigeren Teil der Programmierung, das sogenannte Multithreading. Was es damit auf sich hat, wird im Abschnitt Arbeitsweise näher erläutert.
Das OMSI Plugin Framework besteht aus einer handvoll C++-Klassen, die Deine Variablen und Trigger übersichtlich organisieren, den Umgang mit den 4 Funktionen der Plugin-Schnittstelle regeln und eine einheitliche Schnittstelle zur Bearbeitung der Variablen und Trigger schaffen. Für diese Klassen gibt es eine ausführliche Online-Dokumentation (in exzellentem Denglisch ;-) verfasst).
Da es kaum möglich ist, von Anfang an ein Plugin völlig fehlerfrei zu programmieren (das geht Profis auch nicht anders), gibt es zwei Debug-Hilfen, den OMSI Plugin Log Viewer und das OMSI Plugin Variables Display. Das sind zwei eigenständige Programme, deren Bedienung in einem extra Kapitel erläutert wird.
Außerdem erweitert das OMSI Plugin Framework das Microsoft Visual Studio noch um einen weiteren Compiler. Dieser Compiler hat die Aufgabe, aus einer sehr einfach aufgebauten Textdatei, die die Variablen- und Triggerdeklaration enthält, zum Einen die .opl-Datei für den OMSI zu generieren und zum Anderen zwei weitere Dateien zu erzeugen, die direkt in den Code Deines Plugins einfließen. Diese beiden Dateien enthalten dann Deine Variablen und Trigger in einer für den C++-Compiler nutzbaren Form.
Das ist noch nicht alles. Weiterhin ist eine neue Umgebungsvariable für das Visual Studio vorbereitet, mit der es besonders einfach ist, nach jeder Compilierung die erzeugte DLL und die dazu passende .opl-Datei automatisch in den plugins-Ordner des OMSI zu kopieren.
Die Arbeitsweise des Frameworks
Sobald der OMSI Deine DLL geladen hat, ist Dein Plugin sozusagen Bestandteil des OMSI selbst. Die Aufrufe der 4 Funktionen geschehen somit im Context des OMSI. Um nun der Regel Nummer 1 Rechnung zu tragen, hat das Plugin beim Aufruf der Funktion Start einen weiteren Thread gestartet, der die Aufrufe der Funktionen AccessVariable und AccessTrigger bearbeitet. Das hat für Variablen, auf die nur lesend zugegriffen werden soll den Vorteil, das nur sehr wenig CPU-Zeit für die direkte Bearbeitung der Funktionsaufrufe beansprucht wird. Writable-Variablen und Trigger können davon natürlich nicht profitieren, da ja hier immer auf das Ergebnis der Verarbeitung in Deinem Plugin gewartet werden muss. Für Readonly-Variablen ist noch ein weiterer Beschleunigungsmechanismus implementiert: die Bearbeitungsfunktion in Deinem Plugin wird nur dann aufgerufen, wenn sich der Wert der Variablen seit dem letzten Aufruf verändert hat.
An dieser Stelle ein paar Anmerkungen zum Multithreading. Multithreading ist keinesfalls das Allheilmittel gegen schlechte Frameraten. Ganz im Gegenteil. Wenn man es mit dem Multithreading übertreibt, kann man sogar ganz schnell das umgekehrte Ergebnis erreichen: das Programm wird noch langsamer. Der Grund dafür ist, dass der Prozessor genügend Reserven haben muss, um tatsächlich mehrere Threads parallel auszuführen. Ein Threadwechsel kostet - wie soll es auch anders sein - natürlich auch wieder zusätzliche CPU-Zeit. Mit anderen Worten: auf einem älteren AMD Athlon-XP ein Multithread-Programm auszuführen, bringt gar nichts. Erst wenn der Prozessor wenigstens einen zweiten CPU-Kern hat, kann die Ausführung des Programmes deutlich beschleunigt werden. Wir gehen aber jetzt einfach mal davon aus, dass heutzutage mindestens Dual-Cores oder besser in einem Rechner stecken. Wenn ein Spieler den OMSI tatsächlich noch auf einer alten Single-Core-Maschine laufen lässt, wird er a) ja sowieso wenig Freude am OMSI haben und b) sollte er sich überlegen, ob er dann noch Plugins installiert. Das ist der knallharte Kompromiss, den wir mit diesem Framework eingehen.
Weiter gehts mit der Arbeitsweise. Bei Aufrufen von AccessVariable und AccessTrigger legt das Plugin eine entsprechende Nachricht in der internen Nachrichtenwarteschlange ab und weckt dann den zusätzlichen Thread auf. Bis dahin verbraucht dieser Thread keinerlei CPU-Zeit. Ist die Variable readonly, wird die Kontrolle sofort wieder an den OMSI übergeben. Das geht sehr schnell und belastet den OMSI nur wenig. Der jetzt aktivierte zusätzliche Thread startet nun, parallel zum OMSI, die Verarbeitung der Variaben, indem er die Funktion OnMessage in Deinem Plugin aufruft und legt sich danach wieder schlafen. Bei einer Writable-Variablen und einem Trigger wird ebenfalls OnMessage aufgerufen, allerdings muss der OMSI nun auf das Ende der Bearbeitung warten. Diese Schleife wiederholt sich solange, bis der Spieler das Spiel beendet. Von diesen internen Dingen bekommst Du in Deiner OnMessage-Funktion nichts mit. Das eben ist genau der Vorteil eines Frameworks.
[zum Kapitel 3] | [zum Inhaltsverzeichnis] | [zum Kapitel 5] |