openxray-launcher

OpenXRay Launcher for STALKER games

xr-launcher — universal OpenXRay game installer/launcher

This repository contains xr-launcher — a cross-platform GUI app (Crystal + egui-cr) that assembles playable S.T.A.L.K.E.R. distributions on OpenXRay from copies the user already owns. It does not build the engine and it does not ship game assets: an "install" is a small folder of symlinks + config files pointing at an existing OpenXRay build and an existing GOG/Steam game install.

Supported games:

id game status
soc S.T.A.L.K.E.R.: Shadow of Chernobyl works, experimental engine platform (#392)
cs S.T.A.L.K.E.R.: Clear Sky engine has -cs mode, untested
cop S.T.A.L.K.E.R.: Call of Pripyat engine's native platform

Build

Requires the Crystal toolchain and ruby/rake (for egui-cr's vendored C shims). Then, from the checkout root:

rake all        # deps + native shims + release build -> bin/xr-launcher
rake spec       # headless specs (no egui backend required)

or via crosspack from the repo root:

crosspack build launcher          # linux
crosspack build launcher-macos    # darwin/arm64
crosspack build launcher-windows  # from an x64 Native Tools prompt

egui-cr's shard.yml pins one dependency to an SSH git URL; shards.override.yml in this folder reroutes it over https so plain checkouts work without an SSH key.

What an "install" is

The install wizard asks for three folders — engine, original game, target — and creates:

<target>/
  bin/                 per-file symlinks to the engine build (xr_3da, *.so)
  fsgame.ltx           per-game FS layout; the engine finds it in the cwd
                       (portable mode, see CLocatorAPI::setup_fs_path)
  .installed_ok        JSON marker: game, engine, source, timestamp —
                       both the "is installed" flag and delete protection
  gamedata/
    shaders/gl         symlink to the engine's res/gamedata/shaders/gl
    config[s]/openxray.ltx   [compatibility] game_mode = <soc|cs|cop>
    configs/           (CoP/CS) unpacked configs symlinked from the original
    scripts/           (CoP/CS) shipped scripts copied, engine's updated
                       res/gamedata/scripts overlaid on top
  _appdata_/           savedgames/, logs/, screenshots/ — everything the
                       game writes stays inside the install
  <game data>          SoC: gamedata.db0..dbd symlinks; CoP/CS: levels/,
                       resources/, localization/, mp/, patches/ symlinks

Launch runs bin/xr_3da <mode-flag> with <target> as the working directory (plus the matching -shoc/-cs/-cop flag, so the mode is set by both the config file and the command line). The engine process is detached: closing the launcher does not close the game.

Delete removes only this folder. It refuses to run without .installed_ok, never follows symlinks while deleting, and the original game copy is never touched. Saves live in _appdata_/ and are deleted with the install — the confirmation says so.

Per-game quirks baked into the templates

  • SoC fsgame.ltx uses config\ (not configs\), needs the root-scanning $arch_dir$ line for its .db archives, and its configs/scripts stay inside the archives — only openxray.ltx is overlaid (SoC needs -shoc or the CoP factory breaks spawns in confusing ways).
  • CoP/CS point $arch_dir_levels$/$arch_dir_resources$/… at the symlinked unpacked folders.
  • The SoC/CoP layouts are byte-identical to the field-tested portable rigs (~/soc-openxray, ~/cop-openxray).

i18n (interface languages)

The launcher is fully translated (English / Русский):

  • Translations live in launcher/config/locales/{en,ru}.yml and are embedded into the binary at compile time (I18n::Loader::YAML.embed, crystal-i18n) — a distributed xr-launcher carries its catalogs and needs no locale files on disk. Because of that, builds must run from launcher/ (both the embed and the exml read_file resolve from the compile working directory; the Rakefile and crosspack steps already do).
  • The active language is picked at startup: the saved setting wins, else the system locale (LANG/LC_ALL, ru_RU.UTF-8 → Russian), else English. It is stored as "locale" in launcher.json and switched live from the Settings → Настройки menu (File/Settings/Help menu bar — exml-declarative, assets/launcher.exml) or the combo box on the Settings page; a switch applies on the next frame.
  • The exml markup (menu bar, settings page, status bar) interpolates i18n store slots ({menu_file} …), so translated chrome needs no markup duplication. The dynamic home (game tabs, installs, wizard) renders natively through the same L.t seam.
  • All core messages (validation errors, install log lines, CLI output) go through Launcher::L.t with English fallbacks, so even a headless CLI on a system without the locale still speaks English. spec/i18n_spec.cr enforces that every locale file carries the full key set — a new string without translations fails the spec suite, not the user.

Adding a language: copy en.yml → <code>.yml, translate the values, add the code to Locale::AVAILABLE (src/launcher/i18n.cr). The key-set spec picks the new file up automatically.

Launcher state

  • Per-install truth: <target>/.installed_ok (self-describing; the folder can be moved/removed manually and the launcher notices on the next start).
  • Index + recents: ~/.config/xr-launcher/launcher.json (Linux) / %APPDATA%\xr-launcher\ (Windows) / ~/Library/Application Support/xr-launcher/ (macOS).

CLI (headless)

The GUI binary doubles as a CLI — same file, same logic:

xr-launcher list
xr-launcher install soc --engine ~/xray-16 --source ~/GOG/soc --dir ~/Games/OpenXRay/soc
xr-launcher run    ~/Games/OpenXRay/soc
xr-launcher remove ~/Games/OpenXRay/soc

Desktop shortcut

assets/icons/launcher.png is the app logo (radiation trefoil — generated, no licensing baggage); per-game icons come from misc/media/icons. A Linux menu entry:

[Desktop Entry]
Type=Application
Name=OpenXRay Launcher
Comment=Assemble and run S.T.A.L.K.E.R. on OpenXRay
Exec=/path/to/xr-launcher
Icon=/path/to/launcher/assets/icons/launcher.png
Categories=Game;

assets/xr-launcher.desktop ships this template with TryExec=xr-launcher — install to ~/.local/share/applications/ and fix the icon path, or let a distro package substitute the prefix.

Layout / code map

  src/launcher.cr          library entry + headless CLI (no egui)
  src/launcher_gui.cr      egui-cr GUI: exml chrome + native home — the
                           only egui-dependent file
  src/launcher/i18n.cr     locale init/switch + the L.t lookup seam
  src/launcher/catalog.cr  game definitions: mode flags, fsgame.ltx
                           templates, source validation
  src/launcher/engine.cr   engine folder detection (checkout / bin dir /
                           installed prefix)
  src/launcher/installer.cr  the assembler (symlinks, overlays, marker)
  src/launcher/uninstaller.cr safe recursive delete (marker-gated,
                             symlink-aware)
  src/launcher/runner.cr   detached launch with the right cwd + mode flag
  src/launcher/store.cr    JSON index of installs + locale setting
  src/launcher/paths.cr    per-OS config dirs, marker name
  assets/launcher.exml     declarative UI: menu bar, settings page,
                           status bar (hot-reloads; embedded as a
                           compile-time fallback)
  config/locales/*.yml     embedded translations (en/ru)
  spec/                    headless specs (fake engine + fake game trees,
                           locale key-set completeness)

Verification: rake spec (unit) and the real-world end-to-end — install SoC/CoP from a GOG copy, launch, check _appdata_/logs/ for FATAL / SCRIPT RUNTIME ERROR / early log end, then remove.

Repository

openxray-launcher

Owner
Statistic
  • 0
  • 0
  • 0
  • 0
  • 2
  • about 10 hours ago
  • October 30, 2026
License

Links
Synced at

Fri, 30 Oct 2026 12:37:49 GMT

Languages