Перевод исходной страницы на английском языке для OmsiLaunch 0.1.0-beta3. Нормативной является английская страница: при расхождениях приоритет имеют английская страница и код.
Эта страница — нормативный справочник по LaunchSpec, записи запроса, которая описывает один сеанс OmsiLaunch. Здесь описаны её форма в C# (OmsiLaunch.Api), её форма в виде JSON-файла, который загружает CLI (/spec:<path>, tools/OmsiLaunch.Cli/LaunchSpecJson.cs), каждое свойство с типом, значением по умолчанию, правилом проверки и текущим действием, правила проверки, делающие план неисполнимым, а также приоритет между флагами CLI, файлами спецификации и профилями сеанса. Документируется только то, что делает текущий код.
SessionProfileCompiler.Apply записывает в основу мир, параметры, оформление, интернет-текстуры и поведение из профиля и сохраняет метаданные SessionProfile.
Приведённый ниже полный пример сверен с формой записи. Копия минимального примера поставляется как examples/release-session.example.json (и .omsilaunch\examples\release-session.example.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 допускаются прямые косые черты.
Явная дата, если сборка её поддерживает, записывается как "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 } } }. В этой сборке и то и другое делает план неисполнимым (см. ниже).
проверяется; любой режим, кроме Unset, делает план неисполнимым
PARTIAL
Time
объект TimeSpec
да
нет
проверяется; любой режим, кроме Unset, делает план неисполнимым
PARTIAL
PlayerVehicle
OptionalValue<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.
Для NewMap: обязательно, в форме maps\<dir>\global.cfg (без учёта регистра, / допускается, без ..) и установлено. Для SavedSituation игнорируется (карту задаёт файл .osn).
да (передача при запуске)
STABLE_BETA
SituationIdentity
OptionalValue<string>
Unset
Для SavedSituation: обязательно, идентификатор установленной ситуации situations\...\<file>.osn (в том виде, в каком его возвращают DiscoverAsync(Situations) / /list:situations).
да (передача при запуске)
STABLE_BETA
PresentedEntrypointIndex
OptionalValue<int>
Unset
Для NewMap без EntrypointIdentity: обязательно, >= 0, индекс в списке точек входа карты, который показывает OMSI. Если не задано, передаётся плагину как -1.
да (передача при запуске)
STABLE_BETA
EntrypointIdentity
OptionalValue<string>
Unset
Необработанная метка точки входа или идентификатор из обнаружения контента. Если задано, план становится неисполнимым (world.entrypoint-identity, RUNTIME_PARTIAL, OL_E_CAPABILITY_UNAVAILABLE).
передаётся
PARTIAL
Entrypoint
EntrypointSpec (только для чтения)
вычисляется
Mode = Identity, если задан EntrypointIdentity, иначе PresentedIndex, если задан индекс, иначе Unset; PresentedIndex, Identity повторяют входные значения.
Explicit/System → запись unsupported (world.explicit-date, world.explicit-time, world.explicit-year, STATICALLY_PARTIAL) и OL_E_CAPABILITY_UNAVAILABLE. Режимы также копируются в данные передачи при запуске, которые плагин отклоняет, если режим не Unset (до этого дело не доходит, потому что план неисполним).
SemanticDate: 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 не проверяется.
Идентификатор установленного Vehicles\...\<file>.bus, иначе OL_E_VEHICLE_NOT_FOUND.
разрешается в ResolvedContent; затем player-vehicle.model как неподдерживаемая возможность → OL_E_CAPABILITY_UNAVAILABLE
PARTIAL
Repaint
OptionalValue<string>
Unset
Идентификатор окраски (repaint) для Model (<cti>#item:<n>), иначе OL_E_REPAINT_NOT_FOUND; проверяется только если задан Model.
так же
PARTIAL
Hof
OptionalValue<string>
Unset
Установленный Vehicles\...\<file>.hof, иначе OL_E_HOF_NOT_FOUND.
так же
PARTIAL
FleetNumber
OptionalValue<string>
Unset
Любая строка.
OL_E_CAPABILITY_UNAVAILABLE
PARTIAL
Registration
OptionalValue<string>
Unset
Любая строка.
OL_E_CAPABILITY_UNAVAILABLE
PARTIAL
Enabled
bool (только для чтения)
вычисляется
true, если задан Model. В данных передачи при запуске как PlayerVehicleEnabled передаётся значение PlayerVehicle.IsSet.
производное
PARTIAL
PlayerVehicle с Presence 1 и всеми незаданными полями принимается и ни на что не влияет. Любое заданное поле в этой сборке делает план неисполнимым (STATICALLY_PARTIAL).
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.
Не используется: файлы, которыми владеет сеанс, всегда восстанавливаются точно.
PARTIAL (передаётся, сейчас ни на что не влияет)
SuppressStaleClosecheckWarning
bool
true
любые
true: файл closecheck, существующий до сеанса, безвозвратно удаляется при запуске (диагностическое сообщение closecheck.stale-removed с его SHA-256; при сбое — OL_E_CLOSECHECK_REMOVE_FAILED). false: существующий closecheck не трогается и не считается удалением сеанса. Файл closecheck, который OMSI записывает во время сеанса, всегда удаляется при восстановлении.
STABLE_BETA
StartupTimeoutSeconds
int
180
1..600 (иначе ArgumentOutOfRangeException из StartSessionAsync; флаг CLI /startup-timeout требует 1..600; профили требуют > 0). Бюджет времени от запуска супервизора до состояния Running; по его истечении сеанс завершается сбоем с OL_E_STARTUP_TIMEOUT (плагин запущен) или OL_E_PLUGIN_NOT_LOADED.
да
STABLE_BETA
ShutdownTimeoutSeconds
int
30
любое целое (флаг CLI /shutdown-timeout 1..600)
Не используется: супервизор сразу завершает OMSI через TerminateProcess; кооперативного ожидания завершения нет.
Если задано → input.keyboard как неподдерживаемая возможность (STATICALLY_PARTIAL) и OL_E_CAPABILITY_UNAVAILABLE. Выполнение PATCH/REPLACE для клавиатуры не реализовано.
PARTIAL
ControllerDocument
OptionalValue<string>
Unset
Если задано → input.controller как неподдерживаемая возможность и OL_E_CAPABILITY_UNAVAILABLE.
0Unset (псевдоним Native): собственные файлы заставки OMSI не затрагиваются. 1Managed: OmsiLaunch на время сеанса накладывает overlay на GUI\NewSplashscreen_ENG.bmp и GUI\NewSplashscreen_<LANG>.bmp (после сеанса они точно восстанавливаются).
да
STABLE_BETA (матрица RV-006)
Language
OptionalValue<string>
Unset
PTB/PT-BR, ENG/EN, DEU/DE, FRA/FR (без учёта регистра); любое другое значение нормализуется в ENG. Если не задано, читается значение [language] из options.cfg и нормализуется так же.
да (только для управляемой заставки)
STABLE_BETA
CustomAssetDirectory
OptionalValue<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
SuppressTrayIcon
bool
false
true скрывает отдельный индикатор в трее Windows у владельца CLI.
Только владелец CLI; у API нет трея. Флага CLI нет; значение может прийти только из файла спецификации.
0Native: ничего не меняется. 1Disabled: плагин подавляет встроенный в процесс загрузчик OMSI (телеметрия internet-textures.suppressed / internet-textures.suppression.failed). 2Override: профиль .itx накладывается как overlay в виде Texture\standard.itx; его целевые файлы и Texture\standard.ipr становятся удалениями сеанса.
Обязательно для Override (OL_E_ITX_PROFILE_REQUIRED). Текстовый файл с парами строк: абсолютный URL http/https, затем целевой путь относительно корневого каталога установки, который содержит компонент Texture\, не является корневым, не содержит .., не начинается с \ и не проходит через junction/symlink (OL_E_ITX_PROFILE_INVALID, OL_E_ITX_TARGET_OUTSIDE_TEXTURE_PATH). См. правила путей.
Записываются в диагностическое сообщение плана session_profile.selected (Data["session_profile.*"]). Больше нигде не используются; обычно заполняются компилятором профилей сеанса, а не вручную.
NewMap = 0, SavedSituation = 1, LastMapState = 2, LastSituation = 2 (устаревший псевдоним; это собственная ветвь OMSI для состояния последней карты, а никогда не самый новый файл .osn)
DateTimeMode
Unset = 0, Explicit = 1, System = 2
WeatherMode
Unset = 0, Preset = 1, Icao = 2, RealCurrent = 3
SplashMode
Unset = 0, Native = 0 (псевдоним), Managed = 1
InternetTexturesMode
Native = 0, Disabled = 1, Override = 2
Presence
Unset = 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_FOUND
Installation.RootPath пустое или состоит только из пробелов
LaunchValidation
OL_E_DATE_TIME_APPLY_FAILED
Date.Mode = Explicit без заданного значения или с месяцем/днём вне диапазона; Time.Mode = Explicit без заданного значения или с часом/минутой/секундой вне диапазона
LaunchValidation
OL_E_INVALID_ARGUMENT
Date.Value или Time.Value задано, хотя режим не Explicit
LaunchValidation
OL_E_MAP_NOT_FOUND
NewMap с незаданным MapIdentity или не в форме maps\...\global.cfg (проверка); NewMap с идентификатором, который не установлен (планировщик)
оба
OL_E_ENTRYPOINT_NOT_FOUND
NewMap без EntrypointIdentity и с незаданным или отрицательным PresentedEntrypointIndex
LaunchValidation
OL_E_ENTRYPOINT_REQUIRED
NewMap, карта установлена, EntrypointIdentity нет, PresentedEntrypointIndex не задан (world.presented-entrypoint недоступно)
SessionPlanner
OL_E_SITUATION_NOT_FOUND
SavedSituation без SituationIdentity (проверка) или с идентификатором, который не установлен (планировщик)
оба
OL_E_SITUATION_MAP_NOT_FOUND
SavedSituation: карта, указанная внутри .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_BUILD
Omsi.exe отсутствует, или его размер/SHA-256 не совпадает ни с отпечатком профиля (692EBFBF..., 8 503 440 байт), ни с хешем из списка разрешённых (omsi.profile.OMSI23004)
SessionPlanner
OL_E_CAPABILITY_UNAVAILABLE
World.Mode = LastMapState; задан EntrypointIdentity; режим Date/Time/Year не Unset; режим Weather не Unset; задано любое поле PlayerVehicle; задан Input.KeyboardDocument или Input.ControllerDocument
PlayerVehicle.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_PATH
SessionPlanner
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) строит итоговую спецификацию в следующем порядке:
Основа = встроенные значения по умолчанию или файл /spec, если он указан.
Корневой каталог установки = явный аргумент установки, если он указан, иначе RootPath из основы; затем ./пустое значение → каталог исполняемого файла, Path.GetFullPath. Явный аргумент установки всегда имеет приоритет над RootPath из спецификации.
Профиль сеанса (/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.
Мир: режим мира из CLI всегда имеет приоритет (/new по умолчанию, /saved:<osn>, /last); World.Mode из файла спецификации заменяется. Чтобы запустить сохранённую ситуацию из спецификации, передайте /saved:. /map и /entrypoint//entrypoint-index переопределяют основу; идентификатор /entrypoint из CLI сбрасывает индекс; /saved вместе с /map или флагами точки входа даёт OL_E_INVALID_ARGUMENT.
/no-vehicle сбрасывает PlayerVehicle; отдельные флаги /vehicle, /repaint, /hof, /fleet, /registration переопределяют отдельные поля ТС игрока из основы.
Записи /set:<key>=<value> добавляются в Environment.General (ключ проверяется, значение — нет); остальные семь групп берутся из основы без изменений.
/startup-timeout и /shutdown-timeout переопределяют основу, только если указаны; иначе действуют значение из спецификации, затем из профиля, затем значения по умолчанию 180 s / 30 s. ShutdownTimeoutSeconds для супервизора имеет статус ACCEPTED_FOR_COMPATIBILITY / CURRENTLY_NO_EFFECT (принимается для совместимости, сейчас ни на что не влияет).
/splash, /splash-language, /splash-assets, /internet-textures, /internet-textures-profile переопределяют основу, если указаны; SuppressTrayIcon берётся только из основы.
Флаги диагностики объединяются с основой через логическое ИЛИ.
Итог: явный флаг CLI > профиль сеанса > файл спецификации > встроенное значение по умолчанию, за исключением того, что флаг CLI, конфликтующий с полем, которым владеет профиль, является ошибкой, а не переопределением.
Используется как есть: в файловых операциях относительные пути разрешаются относительно рабочего каталога процесса. Передавайте абсолютный путь. Аренда установки, журнал и каталог контента нормализуют его с помощью Path.GetFullPath.
. или пустое значение = каталог, содержащий OmsiLaunch.exe, и никогда не рабочий каталог вызывающей стороны; явный аргумент установки имеет приоритет над спецификацией; результат преобразуется в абсолютный путь.
Presentation.CustomAssetDirectory
Абсолютный или относительно Installation.RootPath. Должен существовать.
Так же (/splash-assets). Путь assets профиля сеанса ограничен пакетом профиля и сохраняется как абсолютный.
InternetTextures.OverrideProfilePath
Разрешается с помощью Path.GetFullPath, т. е. относительно рабочего каталога процесса, а не корневого каталога установки. Должен существовать.
Так же (/internet-textures-profile). Путь profile профиля сеанса ограничен пакетом и сохраняется как абсолютный.
Целевые строки ITX
Относительно корневого каталога установки; должны содержать компонент Texture\; без корня, без .., без начального \, без компонентов junction/symlink.