Справочник по LaunchSpec

Документация версии v0.1.0-beta.3Исходник на GitHub

Перевод исходной страницы на английском языке для OmsiLaunch 0.1.0-beta3. Нормативной является английская страница: при расхождениях приоритет имеют английская страница и код.

Эта страница — нормативный справочник по LaunchSpec, записи запроса, которая описывает один сеанс OmsiLaunch. Здесь описаны её форма в C# (OmsiLaunch.Api), её форма в виде JSON-файла, который загружает CLI (/spec:<path>, tools/OmsiLaunch.Cli/LaunchSpecJson.cs), каждое свойство с типом, значением по умолчанию, правилом проверки и текущим действием, правила проверки, делающие план неисполнимым, а также приоритет между флагами CLI, файлами спецификации и профилями сеанса. Документируется только то, что делает текущий код.

Связанные страницы: публичный API, справочник по CLI, профили сеанса, коды ошибок, жизненный цикл сеанса, возможности.

Откуда берётся LaunchSpec#

ИсточникКак он превращается в LaunchSpec
APIИнтегратор создаёт запись и передаёт её в PlanSessionAsync.
Флаги CLICliInput.BuildSpecAsync начинает со встроенных значений по умолчанию (NEW_MAP, ничего не задано, значения Behavior по умолчанию) и применяет флаги.
JSON-файл /spec:<path>Загружается методом LaunchSpecJson.LoadAsync, затем используется как исходная основа, которую переопределяют флаги CLI (см. приоритет).
Профиль сеанса (/predefined-profile:<id> /predefined-profile-index:<n>)SessionProfileCompiler.Apply записывает в основу мир, параметры, оформление, интернет-текстуры и поведение из профиля и сохраняет метаданные SessionProfile.

Приведённый ниже полный пример сверен с формой записи. Копия минимального примера поставляется как examples/release-session.example.json (и .omsilaunch\examples\release-session.example.json в релизном пакете).

Форма JSON#

ПравилоПодробности
СериализаторSystem.Text.Json с PropertyNameCaseInsensitive = true, ReadCommentHandling = Skip, AllowTrailingCommas = true; конвертеры не регистрируются.
Имена свойствИмена свойств C# (Installation, RootPath, ...). При загрузке сопоставление не зависит от регистра; CLI записывает их в PascalCase.
ПеречисленияЦелые числа (строкового конвертера перечислений нет). "Mode": 0 допустимо; "Mode": "NewMap" отклоняется как некорректный JSON. Значения перечислены в разделе Перечисления.
OptionalValue<T>Объект { "Presence": 0 | 1, "Value": <T or null> }. Presence 0 = Unset (значение игнорируется), 1 = Set (значение должно присутствовать и не быть null; Set со значением null не проверяется и ведёт себя как недопустимое значение). Опущенный член OptionalValue означает Unset. Член только для чтения IsSet появляется в выводе, который записывает CLI, и при загрузке принимается и игнорируется.
Необязательные записиYear, Weather, Input, Diagnostics, Presentation, InternetTextures, SessionProfile могут быть null или опущены; методы доступа Effective* подставляют значения по умолчанию.
Обязательные записиInstallation, World, Date, Time, Environment (со всеми восемью словарями, используйте {}), Behavior должны быть заданы как объекты. Они не проверяются: значение null или отсутствующая запись приводит к более позднему сбою из-за нулевой ссылки, о котором CLI сообщает как OL_E_INTERNAL (код выхода 10) или OL_E_INVALID_ARGUMENT (код выхода 2).
Неизвестные свойстваОтклоняются до привязки: OL_E_SPEC_UNKNOWN_PROPERTY: $.Path.Name (в пути используются имена членов в том виде, в каком они записаны в файле). Содержимое словарей (Environment.*) не проверяется как свойства.
КореньДолжен быть JSON-объектом: OL_E_SPEC_INVALID. Максимальная глубина вложенности — 32.
Размер файлаНе более 1 MiB (1 048 576 байт): OL_E_SPEC_TOO_LARGE. Файл отсутствует: OL_E_SPEC_NOT_FOUND.
Комментарии и завершающие запятыеКомментарии // и /* */, а также завершающие запятые допускаются.
Некорректный JSONИсключение парсера не преобразуется: CLI сообщает OL_E_INTERNAL с кодом выхода 10.
КодировкаUTF-8 (BOM читатель допускает). Обратные косые черты в идентификаторах должны экранироваться ("maps\\Grundorf\\global.cfg"); для идентификаторов карт, ситуаций, ТС и HOF допускаются прямые косые черты.

Полный пример#

{
  // Comments and trailing commas are accepted. Enums are integers.
  "Installation": {
    "RootPath": ".",                          // "." = directory that contains OmsiLaunch.exe (CLI only)
    "ExpectedExecutableSha256": null          // carried, not consumed
  },
  "World": {
    "Mode": 0,                                // 0 NewMap, 1 SavedSituation, 2 LastMapState (unavailable)
    "MapIdentity": { "Presence": 1, "Value": "maps\\Grundorf\\global.cfg" },
    "SituationIdentity": { "Presence": 0, "Value": null },
    "PresentedEntrypointIndex": { "Presence": 1, "Value": 1 },
    "EntrypointIdentity": { "Presence": 0, "Value": null }
  },
  "Date": { "Mode": 0, "Value": { "Presence": 0, "Value": null } },
  "Time": { "Mode": 0, "Value": { "Presence": 0, "Value": null } },
  "Year": null,
  "Weather": null,
  "PlayerVehicle": { "Presence": 0, "Value": null },
  "Environment": {
    "General": {
      "traffic.randomVehicles": { "Presence": 1, "Value": "150" },
      "graphics.maxFPS": { "Presence": 1, "Value": "60" }
    },
    "Advanced": {}, "Graphics": {}, "AdvancedGraphics": {},
    "Sound": {}, "AiPassengers": {}, "Keyboard": {}, "Controllers": {}
  },
  "Behavior": {
    "RestoreConfiguration": true,             // carried, restore always happens
    "SuppressStaleClosecheckWarning": true,
    "StartupTimeoutSeconds": 180,             // 1..600
    "ShutdownTimeoutSeconds": 30              // carried, not consumed
  },
  "Input": null,
  "Diagnostics": null,
  "Presentation": {
    "Splash": 1,                              // 0 Unset/Native (keep OMSI files), 1 Managed
    "Language": { "Presence": 0, "Value": null },
    "CustomAssetDirectory": { "Presence": 0, "Value": null },
    "SuppressTrayIcon": false
  },
  "InternetTextures": {
    "Mode": 0,                                // 0 Native, 1 Disabled, 2 Override
    "OverrideProfilePath": { "Presence": 0, "Value": null }
  },
  "SessionProfile": null
}

Явная дата, если сборка её поддерживает, записывается как "Date": { "Mode": 1, "Value": { "Presence": 1, "Value": { "Year": 2024, "Month": 5, "Day": 1 } } }, а время — как { "Mode": 1, "Value": { "Presence": 1, "Value": { "Hour": 7, "Minute": 30, "Second": 0 } } }. В этой сборке и то и другое делает план неисполнимым (см. ниже).

Справочник по свойствам#

Столбец «Использование» указывает, что текущий код делает со значением. Для стабильности используется терминология со страницы публичного API.

LaunchSpec (корень)#

СвойствоТип JSONОбязательноЗначение по умолчанию, если опущеноИспользованиеСтабильность
Installationобъект InstallationSpecданетдаSTABLE_BETA
Worldобъект WorldSpecданетдаSTABLE_BETA
Dateобъект DateSpecданетпроверяется; любой режим, кроме Unset, делает план неисполнимымPARTIAL
Timeобъект TimeSpecданетпроверяется; любой режим, кроме Unset, делает план неисполнимымPARTIAL
PlayerVehicleOptionalValue<PlayerVehicleSpec>нетUnsetразрешается для диагностики; любое заданное поле делает план неисполнимымPARTIAL
Environmentобъект EnvironmentSpecданетда (семантический overlay (временная замена файла на время сеанса) файла options.cfg)STABLE_BETA
Behaviorобъект LaunchBehaviorSpecданетчастично (см. запись)STABLE_BETA / PARTIAL
Yearобъект YearSpec или nullнетnull → EffectiveYear = режим Unsetлюбой режим, кроме Unset, делает план неисполнимымPARTIAL
Weatherобъект WeatherSpec или nullнетnull → EffectiveWeather = режим Unsetлюбой режим, кроме Unset, делает план неисполнимымPARTIAL
Inputобъект InputSpec или nullнетnull → EffectiveInput = оба не заданылюбой заданный документ делает план неисполнимымPARTIAL
Diagnosticsобъект DiagnosticsSpec или nullнетnull → EffectiveDiagnostics = значения по умолчаниютолько передаётсяPARTIAL
Presentationобъект SessionPresentationSpec или nullнетnull → EffectivePresentation = управляемая заставка, язык не задан, пользовательский каталог не задан, значок в трее показываетсядаSTABLE_BETA
InternetTexturesобъект InternetTexturesSpec или nullнетnull → EffectiveInternetTextures = NativeдаSTABLE_BETA / EXPERIMENTAL
SessionProfileобъект SessionProfileMetadata или nullнетnullтолько сведения о происхождении (диагностическое сообщение плана session_profile.selected)STABLE_BETA

Методы доступа только для чтения (присутствуют в JSON-выводе CLI, при загрузке игнорируются): EffectiveYear, EffectiveWeather, EffectiveInput, EffectiveDiagnostics, EffectivePresentation, EffectiveInternetTextures.

InstallationSpec#

СвойствоТипПо умолчаниюДопустимые значенияИспользованиеСтабильность
RootPathстрокаобязательноКаталог, содержащий Omsi.exe и plugins\. См. правила путей. Пустое значение или только пробелы → OL_E_INSTALLATION_NOT_FOUND.даSTABLE_BETA
ExpectedExecutableSha256строка или nullnullЛюбая строка.В текущем коде не используется: хост всегда вычисляет хеш Omsi.exe и сравнивает его с профилем сборки, а не с этим значением.PARTIAL (передаётся, сейчас ни на что не влияет)

WorldSpec#

СвойствоТипПо умолчаниюДопустимые значенияИспользованиеСтабильность
ModeWorldMode intобязательно0 NewMap, 1 SavedSituation, 2 LastMapState (LastSituation — устаревший псевдоним с тем же значением 2).да; LastMapState → OL_E_CAPABILITY_UNAVAILABLENewMap, SavedSituation: STABLE_BETA; LastMapState: UNAVAILABLE
MapIdentityOptionalValue<string>UnsetДля NewMap: обязательно, в форме maps\<dir>\global.cfg (без учёта регистра, / допускается, без ..) и установлено. Для SavedSituation игнорируется (карту задаёт файл .osn).да (передача при запуске)STABLE_BETA
SituationIdentityOptionalValue<string>UnsetДля SavedSituation: обязательно, идентификатор установленной ситуации situations\...\<file>.osn (в том виде, в каком его возвращают DiscoverAsync(Situations) / /list:situations).да (передача при запуске)STABLE_BETA
PresentedEntrypointIndexOptionalValue<int>UnsetДля NewMap без EntrypointIdentity: обязательно, >= 0, индекс в списке точек входа карты, который показывает OMSI. Если не задано, передаётся плагину как -1.да (передача при запуске)STABLE_BETA
EntrypointIdentityOptionalValue<string>UnsetНеобработанная метка точки входа или идентификатор из обнаружения контента. Если задано, план становится неисполнимым (world.entrypoint-identity, RUNTIME_PARTIAL, OL_E_CAPABILITY_UNAVAILABLE).передаётсяPARTIAL
EntrypointEntrypointSpec (только для чтения)вычисляетсяMode = Identity, если задан EntrypointIdentity, иначе PresentedIndex, если задан индекс, иначе Unset; PresentedIndex, Identity повторяют входные значения.производноеSTABLE_BETA

DateSpec, TimeSpec, YearSpec#

СвойствоТипПо умолчаниюДопустимые значенияИспользованиеСтабильность
ModeDateTimeMode intобязательно (Year: 0, если запись равна null)0 Unset, 1 Explicit, 2 System.Explicit/System → запись unsupported (world.explicit-date, world.explicit-time, world.explicit-year, STATICALLY_PARTIAL) и OL_E_CAPABILITY_UNAVAILABLE. Режимы также копируются в данные передачи при запуске, которые плагин отклоняет, если режим не Unset (до этого дело не доходит, потому что план неисполним).PARTIAL
ValueOptionalValue<SemanticDate> / OptionalValue<SemanticTime> / OptionalValue<int>UnsetSemanticDate: Year, Month 1..12, Day 1..31; SemanticTime: Hour 0..23, Minute 0..59, Second 0..59. Должно быть задано, если Mode равен Explicit (иначе OL_E_DATE_TIME_APPLY_FAILED), и не должно быть задано, если Mode не равен Explicit (OL_E_INVALID_ARGUMENT). YearSpec.Value не проверяется.только проверяетсяPARTIAL

WeatherSpec#

СвойствоТипПо умолчаниюДопустимые значенияИспользованиеСтабильность
ModeWeatherMode int0, если запись равна null0 Unset, 1 Preset, 2 Icao, 3 RealCurrent.Любой режим, кроме Unset → запись weather как неподдерживаемой возможности и OL_E_CAPABILITY_UNAVAILABLE.PARTIAL
PresetOptionalValue<string>UnsetИмя пресета (не проверяется).передаётсяPARTIAL
IcaoOptionalValue<string>UnsetКод ICAO (не проверяется).передаётсяPARTIAL

PlayerVehicleSpec (внутри PlayerVehicle)#

СвойствоТипПо умолчаниюДопустимые значенияИспользованиеСтабильность
ModelOptionalValue<string>UnsetИдентификатор установленного Vehicles\...\<file>.bus, иначе OL_E_VEHICLE_NOT_FOUND.разрешается в ResolvedContent; затем player-vehicle.model как неподдерживаемая возможность → OL_E_CAPABILITY_UNAVAILABLEPARTIAL
RepaintOptionalValue<string>UnsetИдентификатор окраски (repaint) для Model (<cti>#item:<n>), иначе OL_E_REPAINT_NOT_FOUND; проверяется только если задан Model.так жеPARTIAL
HofOptionalValue<string>UnsetУстановленный Vehicles\...\<file>.hof, иначе OL_E_HOF_NOT_FOUND.так жеPARTIAL
FleetNumberOptionalValue<string>UnsetЛюбая строка.OL_E_CAPABILITY_UNAVAILABLEPARTIAL
RegistrationOptionalValue<string>UnsetЛюбая строка.OL_E_CAPABILITY_UNAVAILABLEPARTIAL
Enabledbool (только для чтения)вычисляетсяtrue, если задан Model. В данных передачи при запуске как PlayerVehicleEnabled передаётся значение PlayerVehicle.IsSet.производноеPARTIAL

PlayerVehicle с Presence 1 и всеми незаданными полями принимается и ни на что не влияет. Любое заданное поле в этой сборке делает план неисполнимым (STATICALLY_PARTIAL).

EnvironmentSpec#

СвойствоТипПо умолчаниюИспользованиеСтабильность
General, Advanced, Graphics, AdvancedGraphics, Sound, AiPassengers, Keyboard, Controllersкаждое — IReadOnlyDictionary<string, OptionalValue<string>>, обязательно ({}, если пусто)нетдаSTABLE_BETA

Восемь групп объединяются; то, в какую группу помещён ключ, ни на что не влияет. Каждая запись с Presence 1 — это семантический параметр из ConfigurationCatalog (src/OmsiLaunch.Configuration/ConfigurationCatalog.cs); ключ определяет целевой файл (options.cfg для всех текущих ключей) и токен. При планировании проверяется, что ключ существует (OL_E_UNKNOWN_SETTING) и доступен для записи (OL_E_SETTING_NOT_WRITABLE); значение проверяется только при запуске (OL_E_INVALID_SETTING_VALUE, сообщается как сеанс в состоянии Failed с OL_E_START_SESSION). Ключи не зависят от регистра. Незаданные записи игнорируются. Флаг CLI /set:<key>=<value> записывает в General; параметры settings профиля сеанса также объединяются в General.

КлючЗначениеПримечания
general.languageстрокатокен [language]
general.radioстрока
general.alternateView, general.showOwnDriver, general.showErrorMessages, general.autoSave, general.currentTime, general.currentDate, general.currentYeartrue / falseтокены присутствия (autoSave — инверсия noAutoSave)
graphics.screenRatioстрока
graphics.maxFPSцелое 10..200
graphics.tileDistanceцелое 1..20
graphics.maxObjectDistanceMetersчисло 20..5000
graphics.minObjectScreenPercentчисло 0..10сохраняется делённым на 100
graphics.minReflectionObjectScreenPercentчисло 0..50сохраняется делённым на 100
graphics.maxObjectComplexityцелое 0..3
graphics.maxMapComplexityцелое 0..2
graphics.sunGlow, graphics.loadAllTiles, graphics.stencilBuffer, graphics.rainReflections, graphics.humansInRainReflectionstrue / falseтокены присутствия
graphics.stencilShadowstrue / falseзаписывается как on / off
graphics.realTimeReflectionseconomy / fullSTATICALLY_PARTIAL
graphics.particlesenabled,maxPerEmitter,playerVehicleOnly,inReflections (bool,int>=0,bool,bool)один блок smokesystems
simulation.collision, simulation.collisionTerrain, simulation.collisionVehicles, simulation.collisionPedestrians, simulation.disableAutomaticScheduleAnalysisPopup, simulation.ticketInfo, simulation.automaticClutchtrue / falseтокены присутствия
simulation.ticketSellingцелое 0..2
simulation.maintenanceцелое 0..4
advanced.reducedMultithreadingtrue / falseсразу два токена OMSI (RUNTIME_PROVEN)
view.driverSmooth, view.driverMoving, controls.autoCenter, controls.reducedSteeringSpeedtrue / falseтокены присутствия
traffic.randomVehiclesцелое 0..1000компонент 0 многострочного блока AIMaxCountRandom (проверено в runtime, матрица RV-005)
traffic.humansцелое 0..1000компонент 1 блока AIMaxCountRandom
traffic.factorPercentчисло 1..300
traffic.parkedVehiclesPercentчисло 0..100
traffic.scheduledVehiclesчисло 0..1000
traffic.scheduledLinePriorityчисло 1..4
traffic.passengerFactorPercentчисло 0..200
sound.stereoчисло 0..100
sound.maxSimultaneousSoundsчисло 5..1000
sound.masterVolumeчисло 0..1
advanced.multithreadingCalculate, advanced.multithreadingTextureLoad, graphics.texture, graphics.textureFilterотклоняютсяизвестны, но недоступны для записи → OL_E_SETTING_NOT_WRITABLE

Изменяемые файлы сохраняют свою кодировку (байты Windows-1252 сохраняются; UTF-8/UTF-16 с меткой BOM учитываются) и окончания строк.

LaunchBehaviorSpec#

СвойствоТипПо умолчаниюДопустимые значенияИспользованиеСтабильность
RestoreConfigurationbooltrueлюбыеНе используется: файлы, которыми владеет сеанс, всегда восстанавливаются точно.PARTIAL (передаётся, сейчас ни на что не влияет)
SuppressStaleClosecheckWarningbooltrueлюбыеtrue: файл closecheck, существующий до сеанса, безвозвратно удаляется при запуске (диагностическое сообщение closecheck.stale-removed с его SHA-256; при сбое — OL_E_CLOSECHECK_REMOVE_FAILED). false: существующий closecheck не трогается и не считается удалением сеанса. Файл closecheck, который OMSI записывает во время сеанса, всегда удаляется при восстановлении.STABLE_BETA
StartupTimeoutSecondsint1801..600 (иначе ArgumentOutOfRangeException из StartSessionAsync; флаг CLI /startup-timeout требует 1..600; профили требуют > 0). Бюджет времени от запуска супервизора до состояния Running; по его истечении сеанс завершается сбоем с OL_E_STARTUP_TIMEOUT (плагин запущен) или OL_E_PLUGIN_NOT_LOADED.даSTABLE_BETA
ShutdownTimeoutSecondsint30любое целое (флаг CLI /shutdown-timeout 1..600)Не используется: супервизор сразу завершает OMSI через TerminateProcess; кооперативного ожидания завершения нет.PARTIAL (передаётся, сейчас ни на что не влияет)

InputSpec#

СвойствоТипПо умолчаниюИспользованиеСтабильность
KeyboardDocumentOptionalValue<string>UnsetЕсли задано → input.keyboard как неподдерживаемая возможность (STATICALLY_PARTIAL) и OL_E_CAPABILITY_UNAVAILABLE. Выполнение PATCH/REPLACE для клавиатуры не реализовано.PARTIAL
ControllerDocumentOptionalValue<string>UnsetЕсли задано → input.controller как неподдерживаемая возможность и OL_E_CAPABILITY_UNAVAILABLE.PARTIAL

DiagnosticsSpec#

СвойствоТипПо умолчаниюИспользованиеСтабильность
LogbooltrueВ src/ не используется. Трассировка хоста <root>\.omsilaunch\diagnostics\<sessionId>-host.log записывается всегда.PARTIAL (передаётся, сейчас ни на что не влияет)
VerboseboolfalseНе используется.PARTIAL
OmsiLogAllboolfalseНе используется.PARTIAL
ProcessTraceboolfalseНе используется.PARTIAL
PluginTraceboolfalseНе используется.PARTIAL
NativeTraceboolfalseНе используется.PARTIAL

Флаги CLI /log, /logall, /omsi-logall, /verbose, /trace, /trace-process, /trace-plugin, /trace-native заполняют эти логические значения (/logall устанавливает Verbose, ProcessTrace, PluginTrace, NativeTrace); они объединяются со значениями спецификации через логическое ИЛИ.

SessionPresentationSpec#

СвойствоТипПо умолчаниюДопустимые значенияИспользованиеСтабильность
SplashSplashMode int1 (Managed)0 Unset (псевдоним Native): собственные файлы заставки OMSI не затрагиваются. 1 Managed: OmsiLaunch на время сеанса накладывает overlay на GUI\NewSplashscreen_ENG.bmp и GUI\NewSplashscreen_<LANG>.bmp (после сеанса они точно восстанавливаются).даSTABLE_BETA (матрица RV-006)
LanguageOptionalValue<string>UnsetPTB/PT-BR, ENG/EN, DEU/DE, FRA/FR (без учёта регистра); любое другое значение нормализуется в ENG. Если не задано, читается значение [language] из options.cfg и нормализуется так же.да (только для управляемой заставки)STABLE_BETA
CustomAssetDirectoryOptionalValue<string>UnsetКаталог, содержащий ENG.bmp и <LANG>.bmp (640×480, 24-битный BMP). См. правила путей. Каталог отсутствует: OL_E_SPLASH_ASSET_DIRECTORY_MISSING; файл отсутствует: OL_E_SPLASH_ASSET_MISSING; неверный формат: OL_E_SPLASH_FORMAT_UNSUPPORTED. Если не задано, используется <root>\.omsilaunch\assets\splash (однократно заполняемый из пакета), иначе — assets\splash из пакета.да (только для управляемой заставки)STABLE_BETA
SuppressTrayIconboolfalsetrue скрывает отдельный индикатор в трее Windows у владельца CLI.Только владелец CLI; у API нет трея. Флага CLI нет; значение может прийти только из файла спецификации.STABLE_BETA

InternetTexturesSpec#

СвойствоТипПо умолчаниюДопустимые значенияИспользованиеСтабильность
ModeInternetTexturesMode int0 (Native)0 Native: ничего не меняется. 1 Disabled: плагин подавляет встроенный в процесс загрузчик OMSI (телеметрия internet-textures.suppressed / internet-textures.suppression.failed). 2 Override: профиль .itx накладывается как overlay в виде Texture\standard.itx; его целевые файлы и Texture\standard.ipr становятся удалениями сеанса.даNative: STABLE_BETA; Disabled, Override: EXPERIMENTAL
OverrideProfilePathOptionalValue<string>UnsetОбязательно для Override (OL_E_ITX_PROFILE_REQUIRED). Текстовый файл с парами строк: абсолютный URL http/https, затем целевой путь относительно корневого каталога установки, который содержит компонент Texture\, не является корневым, не содержит .., не начинается с \ и не проходит через junction/symlink (OL_E_ITX_PROFILE_INVALID, OL_E_ITX_TARGET_OUTSIDE_TEXTURE_PATH). См. правила путей.даEXPERIMENTAL

SessionProfileMetadata#

СвойствоТипИспользованиеСтабильность
Id, Name, Version, Author, PresetId, PresetIndex, PresetName, PackagePathстроки / intЗаписываются в диагностическое сообщение плана session_profile.selected (Data["session_profile.*"]). Больше нигде не используются; обычно заполняются компилятором профилей сеанса, а не вручную.STABLE_BETA

Перечисления#

ПеречислениеЗначения (целое число JSON)
WorldModeNewMap = 0, SavedSituation = 1, LastMapState = 2, LastSituation = 2 (устаревший псевдоним; это собственная ветвь OMSI для состояния последней карты, а никогда не самый новый файл .osn)
DateTimeModeUnset = 0, Explicit = 1, System = 2
WeatherModeUnset = 0, Preset = 1, Icao = 2, RealCurrent = 3
SplashModeUnset = 0, Native = 0 (псевдоним), Managed = 1
InternetTexturesModeNative = 0, Disabled = 1, Override = 2
PresenceUnset = 0, Set = 1
EntrypointMode (только для чтения, Entrypoint.Mode)Unset = 0, PresentedIndex = 1, Identity = 2

Целые числа вне объявленного диапазона сохраняются сериализатором как есть и ведут себя как неизвестные значения (например, неизвестный WorldMode не является ни NEW_MAP, ни SAVED_SITUATION и даёт план без возможности мира; плагин бы его отклонил, но CLI в любом случае заменяет режим, см. раздел о приоритете).

Правила проверки и диагностика неисполнимого плана#

PlanSessionAsync выполняет LaunchValidation.Validate, а затем SessionPlanner.PlanAsync. План исполним ровно тогда, когда ни один код диагностики не начинается с OL_E_. Полный набор:

ДиагностикаУсловиеИсточник
OL_E_INSTALLATION_NOT_FOUNDInstallation.RootPath пустое или состоит только из пробеловLaunchValidation
OL_E_DATE_TIME_APPLY_FAILEDDate.Mode = Explicit без заданного значения или с месяцем/днём вне диапазона; Time.Mode = Explicit без заданного значения или с часом/минутой/секундой вне диапазонаLaunchValidation
OL_E_INVALID_ARGUMENTDate.Value или Time.Value задано, хотя режим не ExplicitLaunchValidation
OL_E_MAP_NOT_FOUNDNewMap с незаданным MapIdentity или не в форме maps\...\global.cfg (проверка); NewMap с идентификатором, который не установлен (планировщик)оба
OL_E_ENTRYPOINT_NOT_FOUNDNewMap без EntrypointIdentity и с незаданным или отрицательным PresentedEntrypointIndexLaunchValidation
OL_E_ENTRYPOINT_REQUIREDNewMap, карта установлена, EntrypointIdentity нет, PresentedEntrypointIndex не задан (world.presented-entrypoint недоступно)SessionPlanner
OL_E_SITUATION_NOT_FOUNDSavedSituation без SituationIdentity (проверка) или с идентификатором, который не установлен (планировщик)оба
OL_E_SITUATION_MAP_NOT_FOUNDSavedSituation: карта, указанная внутри .osn, не установленаSessionPlanner
OL_E_UNSUPPORTED_OPERATING_SYSTEMне Windows 10+ на x64 ОС с x64-процессом хоста (runtime.current-windows-x64)SessionPlanner
OL_E_INSTALLATION_NOT_WRITABLEкорневой каталог отсутствует, установлен атрибут «только для чтения» или нет подкаталога plugins\ (transaction.exact-restore)SessionPlanner
OL_E_UNSUPPORTED_BUILDOmsi.exe отсутствует, или его размер/SHA-256 не совпадает ни с отпечатком профиля (692EBFBF..., 8 503 440 байт), ни с хешем из списка разрешённых (omsi.profile.OMSI23004)SessionPlanner
OL_E_CAPABILITY_UNAVAILABLEWorld.Mode = LastMapState; задан EntrypointIdentity; режим Date/Time/Year не Unset; режим Weather не Unset; задано любое поле PlayerVehicle; задан Input.KeyboardDocument или Input.ControllerDocumentSessionPlanner
OL_E_VEHICLE_NOT_FOUND, OL_E_REPAINT_NOT_FOUND, OL_E_HOF_NOT_FOUNDPlayerVehicle.Model / Repaint / Hof не установлен (в дополнение к OL_E_CAPABILITY_UNAVAILABLE)SessionPlanner
OL_E_UNKNOWN_SETTING, OL_E_SETTING_NOT_WRITABLEключ Environment, которого нет в каталоге / который недоступен для записиSessionPlanner
OL_E_SESSION_PRESENTATION_INVALIDпри построении плана заставки/ITX возникло исключение; сообщение содержит OL_E_SPLASH_ASSET_DIRECTORY_MISSING, OL_E_SPLASH_ASSET_MISSING, OL_E_SPLASH_FORMAT_UNSUPPORTED, OL_E_ITX_PROFILE_REQUIRED, OL_E_ITX_PROFILE_MISSING, OL_E_ITX_PROFILE_INVALID или OL_E_ITX_TARGET_OUTSIDE_TEXTURE_PATHSessionPlanner
OL_E_RUNTIME_ARTIFACT_MISSINGне удаётся загрузить ссылку на замыкание плагина (набор его файлов) (OmsiLaunchRuntimePaths) или релизный манифест (сообщение может содержать OL_E_RELEASE_MANIFEST_INVALID)OmsiLaunchService.PlanSessionAsync

Не проверяется на этапе планирования (приводит к сбою при запуске: сеанс в состоянии Failed с OL_E_START_SESSION): значения параметров (OL_E_INVALID_SETTING_VALUE), целостность постоянного плагина (OL_E_PERMANENT_PLUGIN_*), доступность аренды установки (OL_E_INSTALLATION_BUSY), диапазон StartupTimeoutSeconds (исключение из StartSessionAsync).

Информационные диагностические сообщения плана: plugin.integrity.reference (сообщение manifest или self), session_profile.selected.

Приоритет: флаги CLI, файл спецификации и профиль сеанса#

CliInput.BuildSpecAsync (tools/OmsiLaunch.Cli/Program.cs) строит итоговую спецификацию в следующем порядке:

  1. Основа = встроенные значения по умолчанию или файл /spec, если он указан.
  2. Корневой каталог установки = явный аргумент установки, если он указан, иначе RootPath из основы; затем ./пустое значение → каталог исполняемого файла, Path.GetFullPath. Явный аргумент установки всегда имеет приоритет над RootPath из спецификации.
  3. Профиль сеанса (/predefined-profile + /predefined-profile-index): явные аргументы CLI, затрагивающие поле, которым владеет профиль, отклоняются с OL_E_SESSION_PROFILE_OVERRIDE_CONFLICT (поля мира — только в режиме NEW_MAP; ключи /set, присутствующие в пресете; флаги заставки, если в пресете есть presentation; флаги интернет-текстур, если в нём есть internet-textures; тайм-ауты, если в нём есть behavior). World из основы заменяется новым (сохраняется только режим мира из CLI), затем применяются блок new: профиля (только NEW_MAP), settings (в General), presentation, internet-textures, behavior и метаданные SessionProfile. compatibility.maps применяется для NEW_MAP и SAVED_SITUATION.
  4. Мир: режим мира из CLI всегда имеет приоритет (/new по умолчанию, /saved:<osn>, /last); World.Mode из файла спецификации заменяется. Чтобы запустить сохранённую ситуацию из спецификации, передайте /saved:. /map и /entrypoint//entrypoint-index переопределяют основу; идентификатор /entrypoint из CLI сбрасывает индекс; /saved вместе с /map или флагами точки входа даёт OL_E_INVALID_ARGUMENT.
  5. /date, /time, /year, /weather* переопределяют основу, если указаны (system выбирает DateTimeMode.System).
  6. /no-vehicle сбрасывает PlayerVehicle; отдельные флаги /vehicle, /repaint, /hof, /fleet, /registration переопределяют отдельные поля ТС игрока из основы.
  7. Записи /set:<key>=<value> добавляются в Environment.General (ключ проверяется, значение — нет); остальные семь групп берутся из основы без изменений.
  8. /startup-timeout и /shutdown-timeout переопределяют основу, только если указаны; иначе действуют значение из спецификации, затем из профиля, затем значения по умолчанию 180 s / 30 s. ShutdownTimeoutSeconds для супервизора имеет статус ACCEPTED_FOR_COMPATIBILITY / CURRENTLY_NO_EFFECT (принимается для совместимости, сейчас ни на что не влияет).
  9. /splash, /splash-language, /splash-assets, /internet-textures, /internet-textures-profile переопределяют основу, если указаны; SuppressTrayIcon берётся только из основы.
  10. Флаги диагностики объединяются с основой через логическое ИЛИ.

Итог: явный флаг CLI > профиль сеанса > файл спецификации > встроенное значение по умолчанию, за исключением того, что флаг CLI, конфликтующий с полем, которым владеет профиль, является ошибкой, а не переопределением.

Правила путей#

ПутьПоведение в APIПоведение в CLI
Installation.RootPathИспользуется как есть: в файловых операциях относительные пути разрешаются относительно рабочего каталога процесса. Передавайте абсолютный путь. Аренда установки, журнал и каталог контента нормализуют его с помощью Path.GetFullPath.. или пустое значение = каталог, содержащий OmsiLaunch.exe, и никогда не рабочий каталог вызывающей стороны; явный аргумент установки имеет приоритет над спецификацией; результат преобразуется в абсолютный путь.
Presentation.CustomAssetDirectoryАбсолютный или относительно Installation.RootPath. Должен существовать.Так же (/splash-assets). Путь assets профиля сеанса ограничен пакетом профиля и сохраняется как абсолютный.
InternetTextures.OverrideProfilePathРазрешается с помощью Path.GetFullPath, т. е. относительно рабочего каталога процесса, а не корневого каталога установки. Должен существовать.Так же (/internet-textures-profile). Путь profile профиля сеанса ограничен пакетом и сохраняется как абсолютный.
Целевые строки ITXОтносительно корневого каталога установки; должны содержать компонент Texture\; без корня, без .., без начального \, без компонентов junction/symlink.Так же.
Идентификаторы контента (MapIdentity, SituationIdentity, PlayerVehicle.*)Относительно установки, без учёта регистра, / допускается; никогда не абсолютные.Так же.

Передаётся, но не применяется#

ПолеТекущее действиеСтабильность
Installation.ExpectedExecutableSha256нет (хост сверяет хеш Omsi.exe с профилем сборки)PARTIAL
Behavior.RestoreConfigurationнет (восстановление выполняется всегда)PARTIAL
Behavior.ShutdownTimeoutSecondsнет (принудительное завершение; ACCEPTED_FOR_COMPATIBILITY / CURRENTLY_NO_EFFECT)PARTIAL
Diagnostics.*нет (трассировка хоста записывается всегда)PARTIAL
Input.KeyboardDocument, Input.ControllerDocumentесли задано, план неисполнимPARTIAL
Date, Time, Year (режим, отличный от Unset)план неисполним (STATICALLY_PARTIAL)PARTIAL
Weather (режим, отличный от Unset)план неисполним (STATICALLY_PARTIAL)PARTIAL
PlayerVehicle.* (любое заданное поле)контент разрешается для диагностики, план неисполним (STATICALLY_PARTIAL)PARTIAL
World.EntrypointIdentityплан неисполним (RUNTIME_PARTIAL)PARTIAL
World.Mode = LastMapState / LastSituationплан неисполним (UNSUPPORTED_FOR_CURRENT_PROFILE)UNAVAILABLE
SessionProfileтолько диагностика происхожденияSTABLE_BETA