Plug-in-Schnittstelle

Aus OMSIWiki
Wechseln zu:Navigation, Suche

Hinweis: Änderungen dieses Artikels wurden noch nicht ins Englische übersetzt!

OMSI-Version: 1.00 - 2.00

Allgemeines Prinzip

Es besteht die Möglichkeit, für den OMSI Plugin-DLLs zu programmieren, welche Lese- und Schreibzugriff auf die Fahrzeugvariablen haben und Fahrzeug-Trigger auslösen können.

Jedes Plugin besteht aus einer Konfigurationsdatei mit der Dateiendung *.opl und einer zugehörigen DLL. Beide Dateien müssen im Verzeichnis "OMSI\plugins" liegen.

Beschreibung des Beispiels

In OMSI enthalten ist bereits ein Beispiel-Plugin enthalten. Um es zu aktivieren, muss die Datei "test.txt" im "<OMSI>\plugins"-Verzeichnis in "test.opl" umbenannt werden.

Funktionsumfang

Dieses Plugin hat drei Funktionen: Einen Tacho (analog und digital) ganz oben, einen Sollwertregler für den roten Heizungsregler (obwohl da falscherweise "Rollband-Sollwert" steht) und einen Türtaster "Button1" (der aber trotzdem nur funktioniert, wenn die Haltestellenbremse aktiv und die Elektrik an ist).

Oberfläche des Beispiel-Plugins

Aufbau der *.opl-Datei

To activate, rename this file to "test.opl"

[dll]
Test.dll

[varlist]
2
Velocity
cockpit_heizregler_temp

[triggers]
1
bus_doorfront0

Die erste Zeile ist nur eine Kommentarzeile. Der [dll]-Befehl gibt den Dateinamen der zugehörigen DLL an.

Der [varlist]-Befehl beginnt mit der Anzahl der zu erwartenden (lokalen) Fahrzeugvariablen. Hierbei können auch User-Variablen eines bestimmten Busses angegeben werden. Wenn der tatsächlich gefahrene Bus dann diese Variable nicht hat, dann werden die zugehörigen Zugriffe natürlich nicht durchgeführt.

Die Variable mit dem Index 0 ist also bei dieser DLL "Velocity", die Variable mit dem Index 1 ist "cockpit_heizregler_temp".

Der [triggers]-Befehl beginnt ebenfalls mit der Anzahl der zu erwartenden Fahrzeugtrigger. In diesem Fall ist dies nur ein Trigger: "bus_doorfront0" mit dem Index 0.

Aufbau der DLL

Anhand der Beispiel-DLL wird nun erklärt, wie der zugehörige Delphi-Code aussehen soll. Im Allgemeinen sollte es möglich sein, auch mit anderen Programmiersprachen passende DLLs zu programmieren. Ausprobiert habe ich dies allerdings nicht.

Die DLL besteht aus zwei Units. Erklärt wird aber nur die Hauptunit (Test.dpr) (die zweite Unit enthält nur einige wenige nicht-relevante Implementierungen für die Form):

library Test;

uses
  SysUtils,
  Dialogs,
  Classes,
  TestU in 'TestU.pas' {Form1};

{$R *.res}

procedure Start( AOwner: TComponent ); stdcall;
begin
        form1 := TForm1.Create( AOwner );
        form1.Show;
end;

procedure Finalize; stdcall;
begin
        form1.Free;
end;

procedure AccessVariable( varindex: word; var value: single; var write: boolean ); stdcall;
begin
        case varindex of
                0:
                begin
                        form1.Label2.Caption := floattostrF( value, ffFixed, 5, 1 ) + ' km/h';
                        form1.Gauge1.Progress := round( value );
                        write := false;                        
                end;
                1:
                begin
                        value := form1.TrackBar1.Position / 30;
                        write := true;
                end;
        end;
end;

procedure AccessTrigger( triggerindex: word; var active: boolean ); stdcall;
begin
        case triggerindex of
                0:
                begin
                        active := form1.button1_pressed;
                end;
        end;
end;

exports
        AccessVariable,
        AccessTrigger,        
        Start,
        Finalize;


begin
end.

Zunächst ist der letzte Abschnitt "exports" zu beachten: Die vier gelisteten Prozeduren sollen von der DLL angeboten werden: AccessVariable, AccessTrigger, Start und Finalize.

Die vier Prozeduren haben folgenden Aufbau:

Aufbau der Prozedur Start

Start( AOwner: TComponent ) wird am Anfang aufgerufen und ermöglicht es der DLL, sich zu initialisieren. In diesem Fall wird Form1 erzeugt und der gleichnamigen Variable zugeordnet, welche sich jedoch in der Unit TestU befindet. Als zweiter Schritt wird der Show-Befehl aufgerufen, um die Form1 anzuzeigen. Start übergibt den Parameter "AOwner", welcher der Handler des Hauptprogramms von OMSI darstellt.

Aufbau der Prozedur Finalize

Finalize dagegen wird beim Schließen aufgerufen. Hier wird schlicht das Objekt Form1 zerstört.

Aufbau der Prozedur AccessVariable

Im Betrieb ruft OMSI diese Prozedur für alle in der *.opl-Datei gelisteten lokalen Variablen auf. Sie übergibt dabei stets den Index der Variable (varindex). Die Prozedur kann nun ihrerseits die Variablen value und write schreiben.

Bei einem Lesezugriff kann die Prozedur wie im Beispiel unter "0:" die Variable über value einfach auslesen. Es ist aber wie unter "1" auch möglich, dem Wert von value einen neuen Wert zuzuweisen. Dann aber muss die Variable write auch auf wahr gesetzt werden, damit der Wert von OMSI übernommen wird. Im Beispiel wird die TrackBar ausgelesen und der Wert auf den Wert von value geschrieben.

Aufbau der Prozedur AccessTrigger

Diese Prozedur arbeitet recht ähnlich. Hier allerdings wird die Triggerliste durchgearbeitet. Die DLL kann bei Aufruf dieser Funktion den Wert active auf true setzen; dann löst OMSI den gewünschten Trigger aus.

Ausführliches Tutorial

Ein ausführliches Tutorial zur Nutzung dieser Schnittstelle - allerdings mit der Programmiersprache C++ - ist hier im Wiki in der Kategorie Tutorials zu finden.

Neuerungen OMSI2

Aus Gründen der Kompatibilität wurden die folgenden Prozedurnamen geändert:

Start ==> PluginStart sowie

Finalize ==> PluginFinalize.

Außerdem wurde die *.opl-Datei um die Schlüsselworte [stringvarlist] und [systemvarlist] ergänzt, mit denen nun auch auf String- und Systemvariablen zugegriffen werden kann. Deren Syntax entspricht der von [varlist]. Dementsprechend wurden folgende Methoden ergänzt:

AccessSystemVariable( varindex: word; var value: single; var write: boolean );
AccessStringVariable( varindex: word; str: PWideChar; var write: boolean );