Runtime control

Documentatie voor versie v0.1.0-beta.3Bron bekijken op GitHub

Vertaling van de oorspronkelijke Engelse pagina voor OmsiLaunch 0.1.0-beta3. De Engelse pagina is normatief: bij verschillen gelden de Engelse pagina en de code.

Runtime control is de verzameling lees-, schrijf- en actieoperaties die OmsiLaunch binnen een actieve OMSI-sessie uitvoert. Deze pagina legt uit langs welke drie wegen je deze bereikt (eigenaar-API, CLI-client, lokaal control plane), hoe verzoeken van de aanroeper naar de plugin en terug reizen, hoe handles en verzoekidentiteiten werken, welke timeouts gelden, wat bewust niet in het journal wordt vastgelegd en welke conventies voor argumenten en resultaten gelden, met een uitgewerkt voorbeeld voor elke familie. De inventaris van operaties zelf, met argumenten, resultaatsleutels en fouten, staat in capabilities. Bronnen: OmsiLaunchService.ExecuteRuntimeAsync, CurrentRuntimeCommandStore (src/OmsiLaunch.Process/RuntimeDeployment.cs), CurrentRuntimeCommandMailbox en CurrentRuntimeControl (src/OmsiLaunch.Plugin/CurrentRuntimeControl.cs), LocalControlPlane en CliInput (tools/OmsiLaunch.Cli/).

Drie instappunten#

InstappuntWiePadTimeout
Eigenaar-APIEen integrator die de sessie binnen het eigen proces heeft gestart met IOmsiLaunch.StartSessionAsyncExecuteRuntimeAsync(session, RuntimeCommand, timeout) -> registervalidatie -> sessie opzoeken -> mailboxdoor de aanroeper opgegeven TimeSpan
Eigenaar-CLI (/runtime:<op>)Het OmsiLaunch.exe-proces dat eigenaar van de sessie iséén operatie, direct na Running uitgevoerd; het resultaat wordt naar .omsilaunch\diagnostics\<session>-runtime-operation.json en naar de console geschreven; de sessie loopt door5 s (15 s voor road-vehicles.spawn)
CLI-clientElke aanroep van OmsiLaunch.exe zonder installatieargument, bijvoorbeeld OmsiLaunch.exe time getnamed pipe runtime.execute naar de eigenaar van de installatie waarin het uitvoerbare bestand staat -> de eigenaar roept ExecuteRuntimeAsync aan8 s (30 s voor road-vehicles.spawn) aan zowel de client- als de eigenaarzijde
Lokaal control planeElk proces van dezelfde Windows-gebruikerhetzelfde pipeprotocol als de CLI-client; zie local controlzoals hierboven

Elk pad eindigt in ExecuteRuntimeAsync, dat de openbare grens in deze volgorde afdwingt:

  1. PublicCapabilityRegistry.ValidateRuntimeArguments: een operatie die niet in PublicRuntimeOperationIds staat (inclusief elke internal.*-operatie) retourneert Succeeded=false, ErrorCode=OL_E_RUNTIME_OPERATION_UNKNOWN; een ontbrekend of leeg verplicht argument retourneert OL_E_RUNTIME_ARGUMENT_REQUIRED. Geen van beide raakt de sessie.
  2. Sessie opzoeken (KeyNotFoundException bij een onbekende handle), OL_E_RUNTIME_SESSION_MISMATCH als RuntimeCommand.SessionId van de handle afwijkt, OL_E_SESSION_NOT_RUNNING tenzij de toestand Running is.
  3. Mailboxverzoek (zie hieronder), waarna ScrubInternalValues elke resultaatsleutel verwijdert die begint met internal_ of eindigt op _address, _pointer, _vmt.

De CLI-client en het control plane voeren stap 1 zelf uit voordat ze contact opnemen met de eigenaar, zodat een ongeldige opdrachtnaam als exitcode 2 wordt gerapporteerd, ook als er geen sessie actief is (OL_E_RUNTIME_OPERATION_UNKNOWN en OL_E_RUNTIME_ARGUMENT_REQUIRED worden afgebeeld op InvalidArguments; andere weigeringen op 7; geen eigenaar op 4).

Het control-plane-eindpunt bestaat alleen zolang de eigenaar Running is, na het opstarten en nadat een eventuele /runtime-batch-, /runtime-write-batch- of /d3d-batch-harness is voltooid. Wijzigende opdrachten (runtime.execute, session.stop) moeten de actieve session_id meesturen; de CLI haalt deze automatisch op uit session.status (anders OL_E_CONTROL_SESSION_MISMATCH).

Verzoekidentiteit en de mailbox#

Een RuntimeCommand(SessionId, RequestId, Operation, Arguments) wordt geserialiseerd naar een RuntimeCommandWire-envelope (magic OLRC, versie 1, header van 72 bytes, SHA-256 van de JSON-payload) en klaargezet in de single-flight-mailbox van 64 KiB van de sessie (OmsiLaunch.Runtime.<sessionId>). De plugin pollt de mailbox elke 50 ms op de UI-thread van OMSI, voert de operatie daar uit en schrijft het antwoord.

Regels die het kanaal robuust maken:

RegelEffect
Single flightEén verzoek tegelijk per sessie; de host serialiseert aanroepers met een semafoor. Een slot dat nog requested is wanneer er een nieuw verzoek binnenkomt, geeft OL_E_RUNTIME_CHANNEL_BUSY.
SessiebindingDe plugin negeert (en wist) een verzoek waarvan de sessie-GUID niet de eigen GUID is; de host weigert een antwoord waarvan de sessie- of verzoek-id niet overeenkomt (OL_E_RUNTIME_RESPONSE_INVALID).
TimeoutAls de deadline verstrijkt, zet de host het slot terug op idle en gooit TimeoutException("OL_E_RUNTIME_REQUEST_TIMEOUT").
Laat antwoordDe plugin publiceert een antwoord alleen als het slot nog de eigen verzoek-id bevat; een antwoord op een opgegeven verzoek wordt verworpen. Als er toch een binnenkomt, vindt het volgende hostverzoek een verouderd responded-slot, verwerpt dit en gaat verder; als dat verouderde antwoord dezelfde verzoek-id heeft als het nieuwe verzoek, gooit de host OL_E_RUNTIME_REQUEST_ID_REUSED. Aanroepers mogen daarom binnen een sessie nooit een verzoek-id hergebruiken.
GrootteEen verzoek dat groter is dan het slot wordt vóór het klaarzetten geweigerd (ArgumentOutOfRangeException). Een resultaat van een begrensde lijst dat niet past, wordt door de plugin ingekort (laatste rijen weggelaten, truncated=true, kleinere returned_count); elk ander te groot antwoord wordt vervangen door een getypeerde fout OL_E_RUNTIME_RESPONSE_TOO_LARGE.
Kanaal geslotenNadat de sessie is beëindigd, OL_E_RUNTIME_CHANNEL_CLOSED.

Verzoek-id's zijn ulong-waarden die de aanroeper kiest. De CLI gebruikt vaste bereiken: 10_001 voor /runtime:, 50_001+ voor doorgestuurde control-plane-verzoeken, 1+ voor de leesbatch, 20_000+ voor de D3D-batch, 30_000+ voor D3DRuntimeApi. Integrators horen per sessie een monotoon oplopende teller te gebruiken.

Handles en detectie van verouderde handles#

PrefixTypeUitgegeven doorFormaat
rv-RoadVehicleroad-vehicles.list, road-vehicles.spawn (created_handle), player-vehicle.readrv- + zes decimale cijfers (rv-000003)
hb-Humanhumans.listhb- + zes decimale cijfers
d3dtex-D3D-textured3d.texture.created3dtex-<sessionId N>-<16 hex digits>

Handles zijn ondoorzichtig en gelden per sessie: ze worden door de plugin aangemaakt, coderen nooit een adres en hebben in een andere sessie geen betekenis. Bij het omzetten van een handle controleert de plugin of het adres waarnaar deze verwijst nog in de actieve OMSI-collectie staat (volgens de laatste lijstleesactie; road-vehicles.list en humans.list vernieuwen dit beeld) en leest een objectvingerafdruk opnieuw (de Delphi-VMT plus de pointer naar de voertuigdefinitie, of de modelindex van de mens). Een afwijking betekent dat het native object is vernietigd en het adres is hergebruikt: OL_E_RUNTIME_OBJECT_HANDLE_STALE. Voor hetzelfde actieve object wordt bij herhaalde lijstleesacties opnieuw hetzelfde token geretourneerd. Resterende blinde vlek: een object van dezelfde klasse en definitie dat tussen twee lijstleesacties op hetzelfde adres opnieuw is aangemaakt, kan niet worden onderscheiden. D3D-handles worden door de native brug gevalideerd: een onbekende handle of een handle van een andere sessie geeft OL_E_D3D_STALE_RESOURCE_HANDLE, een vrijgegeven handle OL_E_D3D_RESOURCE_RELEASED, en een wijziging van de apparaatgeneratie markeert textures als STALE.

Handles zijn nooit native adressen en mogen nooit worden geparseerd, numeriek vergeleken, over sessies heen bewaard of aan een andere sessie doorgegeven: behandel ze als ondoorzichtige strings die geldig zijn voor de sessie die ze heeft uitgegeven.

Runtimebewijs: een vrijgegeven D3D-handle blijft geweigerd nadat nieuwe textures zijn aangemaakt, en een handle uit een vorige sessie wordt door de volgende sessie geweigerd (runtime closure H02); een D3D-apparaatreset maakt elke actieve texture ongeldig (OL_E_D3D_STALE_RESOURCE_HANDLE, D01). Detectie van verouderde RoadVehicle- en Human-handles na natuurlijke verwijdering (RV-002) heeft geen veilige runtimeproducent (OMSI heeft in de observatievensters geen objecten verwijderd en geen enkele openbare operatie verwijdert er een); dit is offline gedekt.

Wat niet in het journal wordt vastgelegd#

Runtimewijzigingen veranderen alleen het geheugen van OMSI. Ze worden niet in het transactiejournal vastgelegd en niet hersteld wanneer de sessie eindigt: time.set, camera.set, camera.lock (het beleid stopt wanneer de plugin afsluit), vehicle.variable.set, road-vehicles.spawn, road-vehicles.place-random en elke d3d.texture.*-resource. Ze verdwijnen met het OMSI-proces, dat OmsiLaunch aan het einde van de sessie beëindigt zonder OMSI iets te laten opslaan (zie transacties en recovery). Niets in de runtimefamilie raakt het bestandssysteem.

Conventies voor argumenten en resultaten#

  • Argumenten zijn sleutel/waarde-paren van strings. Op de CLI wordt --key=value na de opdrachtwoorden een runtimeargument (OmsiLaunch.exe vehicles get --handle=rv-000001); /runtime-arg:key=value is het equivalent voor /runtime:<op>. Getallen gebruiken de invariante cultuur (. als decimaalteken); booleans zijn true/false.
  • Opdrachtwoorden worden via CliInput.HierarchicalRoutes op operatie-id's afgebeeld (bijvoorbeeld time get -> time.read, vehicles summary -> road-vehicles.read, scripts variable set -> vehicle.variable.set). De volledige routetabel staat in de CLI-referentie. D3D-operaties hebben geen route met opdrachtwoorden; gebruik /runtime:d3d.status of /runtime:d3d.texture.create --width=8 --height=8 --format=A8R8G8B8.
  • Resultaten zijn platte string-dictionaries. Lijsten gebruiken sleutels van de vorm <row>.<n>.<field> (vehicle.0.handle, track.3.filename, name.12) met count en, waar begrensd, returned_count en truncated.
  • Fouten bevatten Succeeded=false, een OL_E_-ErrorCode en, bij fouten aan de pluginzijde, detail (en native_status bij D3D, exception bij onverwachte fouten).

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" }
  }
}

Een foutenvelope ziet eruit als { "ok": false, "command": ..., "protocol_version": "0.1", "error": { "code": "OL_E_...", "category": "...", "message": "..." } }. Zonder --json drukt de CLI het resultaatobject af als ingesprongen JSON of als CODE: message.

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 gooit een exceptie bij grensovertredingen na de registervalidatie (OL_E_RUNTIME_SESSION_MISMATCH, OL_E_SESSION_NOT_RUNNING, OL_E_RUNTIME_CHANNEL_*, OL_E_RUNTIME_REQUEST_TIMEOUT, OL_E_RUNTIME_RESPONSE_INVALID) en retourneert Succeeded=false bij weigeringen door het register en fouten aan de pluginzijde.

Uitgewerkte voorbeelden#

Alle CLI-voorbeelden gaan ervan uit dat er een eigenaar actief is voor de installatie die OmsiLaunch.exe bevat (gestart met bijvoorbeeld OmsiLaunch.exe /new /map:maps\Grundorf\global.cfg /entrypoint-index:1, of OmsiLaunch.exe "/saved:situations\Linie 5.osn" als een voorbeeld een spelersvoertuig nodig heeft) en worden uitgevoerd vanuit een tweede console in dezelfde installatie.

FamilieOpdrachtWat deze doet
SessieOmsiLaunch.exe session status --jsonLeest SessionId, State, diagnosemeldingen en de begrensde lijst van runtimegebeurtenissen.
TijdOmsiLaunch.exe time get en daarna OmsiLaunch.exe time set --hour=7 --minute=30Leest de klok; zet deze via de geprofileerde SetTime en retourneert de teruggelezen waarde.
WeerOmsiLaunch.exe weather get en OmsiLaunch.exe weather actual getLeest de huidige weertoestand en de actuele/ICAO-weertoestand. OmsiLaunch.exe weather set --wind_speed=1 retourneert OL_E_RUNTIME_SETTING_NOT_PERSISTENT.
KaartOmsiLaunch.exe map getIdentiteit van de kaart, naam, beschrijving, aantal tiles, jaarbereik en verkeerszijde.
CameraOmsiLaunch.exe camera set --field_of_view=50 en daarna OmsiLaunch.exe camera lock --family=0 --preset=1 en OmsiLaunch.exe camera unlockSchrijft de FOV; zet de chauffeursfamilie vast met preset 1 (vereist een spelersvoertuig, bijvoorbeeld uit een opgeslagen situatie); heft het beleid op.
VoertuigenOmsiLaunch.exe vehicles summary, OmsiLaunch.exe vehicles list, OmsiLaunch.exe vehicles get --handle=rv-000001Aantallen; handles; één snapshot.
SpawnenOmsiLaunch.exe vehicles spawn --model=Vehicles\MAN_SD200\MAN_SD77.busMaakt één AI-RoadVehicle aan (timeout 30 s); retourneert created_handle. OmsiLaunch.exe vehicles place-random --group=1 roept PlaceRandomBus aan.
SpelerOmsiLaunch.exe player getpresent=false bij een headless start, anders de snapshot van de speler.
MensenOmsiLaunch.exe humans summary, OmsiLaunch.exe humans list, OmsiLaunch.exe humans get --handle=hb-000001Aantallen; handles; één snapshot.
DienstregelingOmsiLaunch.exe timetable get, OmsiLaunch.exe timetable tracks list, OmsiLaunch.exe timetable logs listAantallen van de manager; begrensde trackrijen; logs van de dienstregeling.
ScriptsOmsiLaunch.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_routeNumerieke variabelen weergeven/lezen/schrijven; stringvariabele lezen.
Constanten en curvesOmsiLaunch.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.5Voertuigconstanten en evaluatie van curves. Namen zijn modelspecifiek: gebruik de namen die de list-opdracht retourneert (deze zijn weergegeven voor de spelersbus van situations\Linie 5.osn).
HOFOmsiLaunch.exe hof get --handle=rv-000001HOF-metadata van de voertuigdefinitie.
Chauffeurs en kaartjesOmsiLaunch.exe drivers list, OmsiLaunch.exe tickets getChauffeursrecords; kaartjespakket.
D3DOmsiLaunch.exe /runtime:d3d.texture.create --width=8 --height=8 --format=A8R8G8B8 en daarna OmsiLaunch.exe /runtime:d3d.texture.update --handle=<HANDLE> --width=8 --height=8 --pixels_base64=<BASE64> en OmsiLaunch.exe /runtime:d3d.texture.release --handle=<HANDLE>Levenscyclus van een texture op de renderthread; <HANDLE> is de handle die create afdrukt; --pixels_base64 moet decoderen tot width * height * 4 bytes (32-bits formaten) en maximaal 48 KiB.
GebeurtenissenOmsiLaunch.exe events read, OmsiLaunch.exe events watchBegrensde lijst van gebeurtenissen; pollend volgen (250 ms) tot Ctrl+C.
StoppenOmsiLaunch.exe session stopVraagt de canonieke stop aan: OMSI wordt beëindigd en de transactie wordt door de eigenaar hersteld.

Stabiliteit#

Het kanaal zelf (runtime.command-channel) is STABLE_BETA: wire-integriteit, sessiebinding, het verwerpen van late antwoorden en getypeerde weigering bij te grote omvang zijn offline gedekt door runtime-command.wire-guard, runtime-command.session-binding en runtime-command.late-response-ignored, en tijdens runtime door RV-003 (sessie 5f641c8d), Round A RA-019 (een client gaf road-vehicles.spawn na 250 ms op; het volgende verzoek slaagde) en de kanaaltestreeks R03 van de runtime closure (timeout, annulering, hergebruikte verzoek-id, weigering door de plugin, interne operatie, verkeerde sessie en ontbrekend argument, telkens gevolgd door een geslaagd verzoek). De stabiliteit per operatie staat in capabilities.

Hergebruik van het kanaal na fouten#

Elk eindpad van een runtimeverzoek laat de mailbox herbruikbaar achter: succes, een getypeerde fout, een misvormd of te groot antwoord, een antwoord van een andere sessie of met een verkeerde verzoek-id, een timeout, annulering door de aanroeper en decodeerfouten eindigen allemaal in één opruimstap die het slot terugzet op idle en de lengte en de envelope-header wist, zodat niets van een eerder verzoek door het volgende kan worden gelezen. Een achtergebleven verzoek of antwoord dat wordt aangetroffen wanneer een nieuw verzoek begint, wordt eerst gewist (OL_E_RUNTIME_REQUEST_ID_REUSED als het de id van het nieuwe verzoek draagt). Aan de pluginzijde wordt een exceptie binnen een operatie beantwoord met OL_E_RUNTIME_OPERATION_FAILED, een resultaat dat groter is dan het slot met OL_E_RUNTIME_RESPONSE_TOO_LARGE (een vaste, kleine envelope), een verzoek voor een andere sessie met OL_E_RUNTIME_SESSION_MISMATCH, en een verzoek dat de host heeft opgegeven, wordt nooit beantwoord. Deze regels zijn offline gedekt (runtime-command.terminal-paths-leave-channel-usable, plugin-runtime.oversized-and-abandoned-responses, plugin-runtime.bounded-list-fits-slot); de paden die een aanroeper kan veroorzaken (timeout, annulering, hergebruikte id, getypeerde weigeringen, laat antwoord) hebben ook runtimebewijs (RA-019, R03). Corrupte, vreemde of te grote antwoorden kunnen niet van buiten het product worden veroorzaakt en blijven alleen offline gedekt.