Runtime-Steuerung

Dokumentation für Version v0.1.0-beta.3Quelle auf GitHub ansehen

Übersetzung der englischen Originalseite für OmsiLaunch 0.1.0-beta3. Maßgeblich ist die englische Seite: Bei Abweichungen gelten die englische Seite und der Code.

Die Runtime-Steuerung umfasst die Lese-, Schreib- und Aktionsoperationen, die OmsiLaunch innerhalb einer laufenden OMSI-Sitzung ausführt. Diese Seite erklärt die drei Zugangswege (Eigentümer-API, CLI-Client, lokale Steuerungsebene), wie Anfragen vom Aufrufer zum Plugin und zurück gelangen, wie Handles und Anfrageidentitäten funktionieren, welche Timeouts gelten, was bewusst nicht im Journal erfasst wird, sowie die Konventionen für Argumente und Ergebnisse, jeweils mit einem ausgearbeiteten Beispiel pro Familie. Das Verzeichnis der Operationen selbst, mit Argumenten, Ergebnisschlüsseln und Fehlern, steht unter Capabilities. Quellen: OmsiLaunchService.ExecuteRuntimeAsync, CurrentRuntimeCommandStore (src/OmsiLaunch.Process/RuntimeDeployment.cs), CurrentRuntimeCommandMailbox und CurrentRuntimeControl (src/OmsiLaunch.Plugin/CurrentRuntimeControl.cs), LocalControlPlane und CliInput (tools/OmsiLaunch.Cli/).

Drei Einstiegspunkte#

EinstiegspunktWerPfadTimeout
Eigentümer-APIEin Integrator, der die Sitzung im eigenen Prozess mit IOmsiLaunch.StartSessionAsync gestartet hatExecuteRuntimeAsync(session, RuntimeCommand, timeout) -> Registry-Validierung -> Sitzungssuche -> Mailboxvom Aufrufer übergebene TimeSpan
Eigentümer-CLI (/runtime:<op>)Der OmsiLaunch.exe-Prozess, dem die Sitzung gehörteine Operation, die direkt nach Running ausgeführt wird; das Ergebnis wird nach .omsilaunch\diagnostics\<session>-runtime-operation.json und auf die Konsole geschrieben; die Sitzung läuft weiter5 s (15 s für road-vehicles.spawn)
CLI-ClientJeder Aufruf von OmsiLaunch.exe ohne Installationsargument, z. B. OmsiLaunch.exe time getNamed Pipe runtime.execute zum Eigentümer der Installation, in der sich die ausführbare Datei befindet -> der Eigentümer ruft ExecuteRuntimeAsync auf8 s (30 s für road-vehicles.spawn) sowohl auf Client- als auch auf Eigentümerseite
Lokale Steuerungsebene (Control Plane)Jeder Prozess desselben Windows-Benutzersdasselbe Pipe-Protokoll wie der CLI-Client; siehe lokale Steuerungwie oben

Jeder Pfad endet in ExecuteRuntimeAsync, das die öffentliche Grenze in dieser Reihenfolge durchsetzt:

  1. PublicCapabilityRegistry.ValidateRuntimeArguments: Eine Operation, die nicht in PublicRuntimeOperationIds enthalten ist (einschließlich jeder internal.*-Operation), liefert Succeeded=false, ErrorCode=OL_E_RUNTIME_OPERATION_UNKNOWN; ein fehlendes oder leeres erforderliches Argument liefert OL_E_RUNTIME_ARGUMENT_REQUIRED. Keiner der beiden Fälle berührt die Sitzung.
  2. Sitzungssuche (KeyNotFoundException bei einem unbekannten Handle), OL_E_RUNTIME_SESSION_MISMATCH, wenn RuntimeCommand.SessionId vom Handle abweicht, OL_E_SESSION_NOT_RUNNING, sofern der Zustand nicht Running ist.
  3. Mailbox-Anfrage (siehe unten), danach entfernt ScrubInternalValues jeden Ergebnisschlüssel, der mit internal_ beginnt oder auf _address, _pointer, _vmt endet.

Der CLI-Client und die Steuerungsebene führen Schritt 1 selbst aus, bevor sie den Eigentümer kontaktieren, sodass ein ungültiger Befehlsname auch dann mit Exitcode 2 gemeldet wird, wenn keine Sitzung aktiv ist (OL_E_RUNTIME_OPERATION_UNKNOWN und OL_E_RUNTIME_ARGUMENT_REQUIRED werden auf InvalidArguments abgebildet; andere Ablehnungen auf 7; kein Eigentümer auf 4).

Der Endpunkt der Steuerungsebene existiert nur, solange der Eigentümer im Zustand Running ist, nach dem Start und nachdem ein eventuelles /runtime-batch-, /runtime-write-batch- oder /d3d-batch-Harness abgeschlossen ist. Verändernde Befehle (runtime.execute, session.stop) müssen die aktive session_id mitführen; die CLI ermittelt sie automatisch über session.status (andernfalls OL_E_CONTROL_SESSION_MISMATCH).

Anfrageidentität und die Mailbox#

Ein RuntimeCommand(SessionId, RequestId, Operation, Arguments) wird in ein RuntimeCommandWire-Envelope serialisiert (Magic OLRC, Version 1, 72-Byte-Header, SHA-256 der JSON-Nutzdaten) und in der Single-Flight-Mailbox der Sitzung von 64 KiB (OmsiLaunch.Runtime.<sessionId>) bereitgestellt. Das Plugin fragt die Mailbox alle 50 ms auf OMSIs UI-Thread ab, führt die Operation dort aus und schreibt die Antwort.

Regeln, die den Kanal robust machen:

RegelWirkung
Single FlightEine Anfrage gleichzeitig pro Sitzung; der Host serialisiert Aufrufer mit einem Semaphor. Ein Slot, der beim Eintreffen einer neuen Anfrage noch requested ist, ergibt OL_E_RUNTIME_CHANNEL_BUSY.
SitzungsbindungDas Plugin ignoriert (und leert) eine Anfrage, deren Sitzungs-GUID nicht seine eigene ist; der Host lehnt eine Antwort ab, deren Sitzungs- oder Anfrage-ID nicht übereinstimmt (OL_E_RUNTIME_RESPONSE_INVALID).
TimeoutWenn die Frist abläuft, setzt der Host den Slot auf idle zurück und wirft TimeoutException("OL_E_RUNTIME_REQUEST_TIMEOUT").
Verspätete AntwortDas Plugin veröffentlicht eine Antwort nur, wenn der Slot noch seine Anfrage-ID enthält; eine Antwort auf eine aufgegebene Anfrage wird verworfen. Landet dennoch eine, findet die nächste Host-Anfrage einen veralteten responded-Slot vor, verwirft ihn und fährt fort; trägt diese veraltete Antwort dieselbe Anfrage-ID wie die neue Anfrage, wirft der Host OL_E_RUNTIME_REQUEST_ID_REUSED. Aufrufer dürfen daher eine Anfrage-ID innerhalb einer Sitzung niemals wiederverwenden.
GrößeEine Anfrage, die größer als der Slot ist, wird vor der Bereitstellung abgelehnt (ArgumentOutOfRangeException). Ein Ergebnis einer begrenzten Liste, das nicht passt, wird vom Plugin gekürzt (letzte Zeilen verworfen, truncated=true, kleineres returned_count); jede andere übergroße Antwort wird durch einen typisierten OL_E_RUNTIME_RESPONSE_TOO_LARGE-Fehler ersetzt.
Kanal geschlossenNach dem Ende der Sitzung OL_E_RUNTIME_CHANNEL_CLOSED.

Anfrage-IDs sind vom Aufrufer gewählte ulong-Werte. Die CLI verwendet feste Bereiche: 10_001 für /runtime:, 50_001+ für weitergeleitete Anfragen der Steuerungsebene, 1+ für den Lese-Batch, 20_000+ für den D3D-Batch, 30_000+ für D3DRuntimeApi. Integratoren sollten pro Sitzung einen monoton steigenden Zähler verwenden.

Handles und Erkennung veralteter Handles#

PräfixTypAusgegeben vonFormat
rv-RoadVehicleroad-vehicles.list, road-vehicles.spawn (created_handle), player-vehicle.readrv- + sechs Dezimalziffern (rv-000003)
hb-Humanhumans.listhb- + sechs Dezimalziffern
d3dtex-D3D-Texturd3d.texture.created3dtex-<sessionId N>-<16 hex digits>

Handles sind opak und an die Sitzung gebunden: Sie werden vom Plugin erzeugt, codieren nie eine Adresse und sind in einer anderen Sitzung bedeutungslos. Wird ein Handle aufgelöst, prüft das Plugin, ob die zugeordnete Adresse noch in der aktiven OMSI-Sammlung liegt (Stand des letzten Listenlesevorgangs; road-vehicles.list und humans.list aktualisieren diese Sicht), und liest einen Objekt-Fingerabdruck erneut (die Delphi-VMT plus den Zeiger auf die Fahrzeugdefinition bzw. den Modellindex des Menschen). Eine Abweichung bedeutet, dass das native Objekt zerstört und seine Adresse wiederverwendet wurde: OL_E_RUNTIME_OBJECT_HANDLE_STALE. Für dasselbe aktive Objekt wird bei wiederholten Listenlesevorgängen erneut dasselbe Token zurückgegeben. Verbleibender blinder Fleck: Ein Objekt derselben Klasse und Definition, das zwischen zwei Listenlesevorgängen an derselben Adresse neu erzeugt wird, lässt sich nicht unterscheiden. D3D-Handles werden von der nativen Bridge validiert: Ein unbekanntes Handle oder eines aus einer fremden Sitzung ergibt OL_E_D3D_STALE_RESOURCE_HANDLE, ein freigegebenes OL_E_D3D_RESOURCE_RELEASED, und ein Wechsel der Gerätegeneration markiert Texturen als STALE.

Handles sind niemals native Adressen und dürfen niemals geparst, numerisch verglichen, über Sitzungen hinweg gespeichert oder an eine andere Sitzung übergeben werden: Behandeln Sie sie als opake Zeichenfolgen, die für die ausgebende Sitzung gültig sind.

Runtime-Nachweis: Ein freigegebenes D3D-Handle bleibt abgelehnt, nachdem neue Texturen erzeugt wurden, und ein Handle aus einer vorherigen Sitzung wird von der nächsten abgelehnt (Runtime-Abschluss H02); ein D3D-Geräte-Reset invalidiert jede aktive Textur (OL_E_D3D_STALE_RESOURCE_HANDLE, D01). Für die Erkennung veralteter RoadVehicle- und Human-Handles nach natürlichem Entfernen (RV-002) gibt es keinen sicheren Runtime-Erzeuger (OMSI hat in den Beobachtungsfenstern keine Objekte entfernt, und keine öffentliche Operation entfernt eines); sie ist offline abgedeckt.

Was nicht im Journal erfasst wird#

Runtime-Änderungen verändern nur OMSIs Speicher. Sie werden nicht im Transaktionsjournal erfasst und nicht wiederhergestellt, wenn die Sitzung endet: time.set, camera.set, camera.lock (die Richtlinie endet, wenn das Plugin herunterfährt), vehicle.variable.set, road-vehicles.spawn, road-vehicles.place-random und jede d3d.texture.*-Ressource. Sie verschwinden mit dem OMSI-Prozess, den OmsiLaunch am Ende der Sitzung beendet, ohne OMSI etwas speichern zu lassen (siehe Transaktionen und Recovery). Nichts in der Runtime-Familie berührt das Dateisystem.

Konventionen für Argumente und Ergebnisse#

  • Argumente sind Schlüssel/Wert-Paare aus Zeichenfolgen. In der CLI wird --key=value nach den Befehlswörtern zu einem Runtime-Argument (OmsiLaunch.exe vehicles get --handle=rv-000001); /runtime-arg:key=value ist das Äquivalent für /runtime:<op>. Zahlen verwenden die invariante Kultur (. als Dezimaltrennzeichen); boolesche Werte sind true/false.
  • Befehlswörter werden über CliInput.HierarchicalRoutes auf Operations-IDs abgebildet (z. B. time get -> time.read, vehicles summary -> road-vehicles.read, scripts variable set -> vehicle.variable.set). Die vollständige Routentabelle steht in der CLI-Referenz. D3D-Operationen haben keine Befehlswort-Route; verwenden Sie /runtime:d3d.status oder /runtime:d3d.texture.create --width=8 --height=8 --format=A8R8G8B8.
  • Ergebnisse sind flache Dictionaries aus Zeichenfolgen. Listen verwenden Schlüssel der Form <row>.<n>.<field> (vehicle.0.handle, track.3.filename, name.12) mit count und, sofern begrenzt, returned_count und truncated.
  • Fehlschläge tragen Succeeded=false, einen OL_E_-ErrorCode und bei Fehlschlägen auf Plugin-Seite detail (sowie native_status bei D3D, exception bei unerwarteten Fehlern).

CLI-Envelope (--json)#

{
  "ok": true,
  "command": "time.read",
  "protocol_version": "0.1",
  "result": {
    "SessionId": "5f641c8d-5828-42a9-b811-5e45b9d05533",
    "RequestId": 50001,
    "Succeeded": true,
    "ErrorCode": null,
    "Values": { "hour": "6", "minute": "31", "second": "12", "day": "20", "month": "9", "year": "2026" }
  }
}

Ein Fehler-Envelope hat die Form { "ok": false, "command": ..., "protocol_version": "0.1", "error": { "code": "OL_E_...", "category": "...", "message": "..." } }. Ohne --json gibt die CLI das Ergebnisobjekt als eingerücktes JSON oder als CODE: message aus.

API-Envelope#

var result = await launch.ExecuteRuntimeAsync(session,
    new RuntimeCommand(session.SessionId, requestId++, "vehicle.variable.set",
        new Dictionary<string, string> { ["handle"] = "rv-000001", ["name"] = "Refresh_Strings", ["value"] = "1" }),
    TimeSpan.FromSeconds(5));
if (!result.Succeeded) Console.WriteLine(result.ErrorCode);
else Console.WriteLine(result.Values!["value"]);

ExecuteRuntimeAsync wirft bei Grenzverletzungen nach der Registry-Validierung eine Ausnahme (OL_E_RUNTIME_SESSION_MISMATCH, OL_E_SESSION_NOT_RUNNING, OL_E_RUNTIME_CHANNEL_*, OL_E_RUNTIME_REQUEST_TIMEOUT, OL_E_RUNTIME_RESPONSE_INVALID) und gibt bei Ablehnungen durch die Registry und Fehlern auf Plugin-Seite Succeeded=false zurück.

Ausgearbeitete Beispiele#

Alle CLI-Beispiele setzen voraus, dass für die Installation, die OmsiLaunch.exe enthält, ein Eigentümer läuft (gestartet z. B. mit OmsiLaunch.exe /new /map:maps\Grundorf\global.cfg /entrypoint-index:1 oder mit OmsiLaunch.exe "/saved:situations\Linie 5.osn", wenn ein Beispiel ein Spielerfahrzeug benötigt), und werden aus einer zweiten Konsole in derselben Installation ausgeführt.

FamilieBefehlWas er bewirkt
SitzungOmsiLaunch.exe session status --jsonLiest SessionId, State, Diagnosen und die begrenzte Liste der Runtime-Ereignisse.
ZeitOmsiLaunch.exe time get, danach OmsiLaunch.exe time set --hour=7 --minute=30Liest die Uhr; stellt sie über das profilierte SetTime und gibt den zurückgelesenen Wert zurück.
WetterOmsiLaunch.exe weather get und OmsiLaunch.exe weather actual getLiest den aktuellen Wetterzustand und den Echtwetter-/ICAO-Zustand. OmsiLaunch.exe weather set --wind_speed=1 gibt OL_E_RUNTIME_SETTING_NOT_PERSISTENT zurück.
KarteOmsiLaunch.exe map getKartenidentität, Name, Beschreibung, Kachelanzahl, Jahresbereich und Verkehrsseite.
KameraOmsiLaunch.exe camera set --field_of_view=50, danach OmsiLaunch.exe camera lock --family=0 --preset=1 und OmsiLaunch.exe camera unlockSchreibt das FOV; fixiert die Fahrerfamilie mit Preset 1 (erfordert ein Spielerfahrzeug, z. B. aus einer gespeicherten Situation); gibt die Richtlinie frei.
FahrzeugeOmsiLaunch.exe vehicles summary, OmsiLaunch.exe vehicles list, OmsiLaunch.exe vehicles get --handle=rv-000001Anzahlen; Handles; ein Snapshot.
SpawnOmsiLaunch.exe vehicles spawn --model=Vehicles\MAN_SD200\MAN_SD77.busErzeugt ein KI-RoadVehicle (Timeout 30 s); gibt created_handle zurück. OmsiLaunch.exe vehicles place-random --group=1 ruft PlaceRandomBus auf.
SpielerOmsiLaunch.exe player getpresent=false bei einem Headless-Start, andernfalls der Snapshot des Spielers.
MenschenOmsiLaunch.exe humans summary, OmsiLaunch.exe humans list, OmsiLaunch.exe humans get --handle=hb-000001Anzahlen; Handles; ein Snapshot.
FahrplanOmsiLaunch.exe timetable get, OmsiLaunch.exe timetable tracks list, OmsiLaunch.exe timetable logs listAnzahlen des Managers; begrenzte Track-Zeilen; Fahrplan-Logs.
SkripteOmsiLaunch.exe scripts variable list --handle=rv-000001, OmsiLaunch.exe scripts variable get --handle=rv-000001 --name=Refresh_Strings, OmsiLaunch.exe scripts variable set --handle=rv-000001 --name=Refresh_Strings --value=1, OmsiLaunch.exe scripts string get --handle=rv-000001 --name=act_routeNumerische Variablen auflisten/lesen/schreiben; String-Variable lesen.
Konstanten und KurvenOmsiLaunch.exe constants list --handle=rv-000001, OmsiLaunch.exe constants get --handle=rv-000001 --name=antrieb_getr_version, OmsiLaunch.exe curves list --handle=rv-000001, OmsiLaunch.exe curves evaluate --handle=rv-000001 --name=retarder_stufe1 --x=0.5Fahrzeugkonstanten und Kurvenauswertung. Die Namen sind modellspezifisch: Verwenden Sie die vom list-Befehl zurückgegebenen Namen (diese wurden für den Spielerbus von situations\Linie 5.osn aufgelistet).
HOFOmsiLaunch.exe hof get --handle=rv-000001HOF-Metadaten der Fahrzeugdefinition.
Fahrer und FahrscheineOmsiLaunch.exe drivers list, OmsiLaunch.exe tickets getFahrerdatensätze; Fahrscheinpaket.
D3DOmsiLaunch.exe /runtime:d3d.texture.create --width=8 --height=8 --format=A8R8G8B8, danach OmsiLaunch.exe /runtime:d3d.texture.update --handle=<HANDLE> --width=8 --height=8 --pixels_base64=<BASE64> und OmsiLaunch.exe /runtime:d3d.texture.release --handle=<HANDLE>Texturlebenszyklus auf dem Render-Thread; <HANDLE> ist das von create ausgegebene handle; --pixels_base64 muss zu width * height * 4 Bytes (32-Bit-Formate) und höchstens 48 KiB dekodieren.
EreignisseOmsiLaunch.exe events read, OmsiLaunch.exe events watchBegrenzte Ereignisliste; abfragende Beobachtung (250 ms) bis Ctrl+C.
StoppOmsiLaunch.exe session stopFordert den kanonischen Stopp an: OMSI wird beendet und die Transaktion vom Eigentümer wiederhergestellt.

Stabilität#

Der Kanal selbst (runtime.command-channel) ist STABLE_BETA: Wire-Integrität, Sitzungsbindung, Verwerfen verspäteter Antworten und typisierte Ablehnung übergroßer Daten sind offline durch runtime-command.wire-guard, runtime-command.session-binding und runtime-command.late-response-ignored abgedeckt und zur Laufzeit durch RV-003 (Sitzung 5f641c8d), Round A RA-019 (ein Client gab road-vehicles.spawn nach 250 ms auf; die nächste Anfrage war erfolgreich) und die Kanal-Testreihe R03 des Runtime-Abschlusses (Timeout, Abbruch, wiederverwendete Anfrage-ID, Ablehnung durch das Plugin, interne Operation, falsche Sitzung und fehlendes Argument, jeweils gefolgt von einer erfolgreichen Anfrage). Die Stabilität pro Operation steht unter Capabilities.

Wiederverwendung des Kanals nach Fehlschlägen#

Jeder terminale Pfad einer Runtime-Anfrage hinterlässt die Mailbox wiederverwendbar: Erfolg, ein typisierter Fehler, eine fehlerhaft aufgebaute, übergroße, sitzungsfremde oder mit falscher Anfrage-ID versehene Antwort, Timeout, Abbruch durch den Aufrufer und Dekodierfehler enden alle in einer einzigen Bereinigung, die den Slot auf idle zurücksetzt und Länge und Envelope-Header leert, sodass nichts aus einer früheren Anfrage von der nächsten gelesen werden kann. Eine übrig gebliebene Anfrage oder Antwort, die beim Start einer neuen Anfrage vorgefunden wird, wird zuerst geleert (OL_E_RUNTIME_REQUEST_ID_REUSED, wenn sie die ID der neuen Anfrage trägt). Auf Plugin-Seite wird eine Ausnahme innerhalb einer Operation mit OL_E_RUNTIME_OPERATION_FAILED beantwortet, ein Ergebnis, das größer als der Slot ist, mit OL_E_RUNTIME_RESPONSE_TOO_LARGE (ein festes, kleines Envelope), eine Anfrage für eine andere Sitzung mit OL_E_RUNTIME_SESSION_MISMATCH, und eine Anfrage, die der Host aufgegeben hat, wird nie beantwortet. Diese Regeln sind offline abgedeckt (runtime-command.terminal-paths-leave-channel-usable, plugin-runtime.oversized-and-abandoned-responses, plugin-runtime.bounded-list-fits-slot); die Pfade, die ein Aufrufer herbeiführen kann (Timeout, Abbruch, wiederverwendete ID, typisierte Ablehnungen, verspätete Antwort), haben zusätzlich einen Runtime-Nachweis (RA-019, R03). Beschädigte, sitzungsfremde oder übergroße Antworten lassen sich von außerhalb des Produkts nicht erzeugen und sind nur offline abgedeckt.