476 lines
20 KiB
Markdown
476 lines
20 KiB
Markdown
<!-- Generated from the Runi source repository at v0.4.0. -->
|
|
<!-- Edit the original there, not this copy. -->
|
|
|
|
# User flows
|
|
|
|
See [config-schema.md](config-schema.md) for the exact fields referenced
|
|
below, and architecture.md (source repository) for how `run` resolves all of
|
|
this internally.
|
|
|
|
## 1. First run on a fresh machine
|
|
|
|
`runi versions` auto-discovers whatever's already installed (Steam's
|
|
official Proton if Steam is present; nothing else yet). To get GE-Proton:
|
|
`runi versions list-remote --source ge-proton` shows installable
|
|
releases, `runi versions install ge-proton latest` downloads, verifies
|
|
checksum, extracts into `compatibilitytools.d` with a progress bar, and now
|
|
shows up in `runi versions`.
|
|
|
|
## 2. Add and run a standalone `.exe` (no storefront)
|
|
|
|
```
|
|
runi add ~/Games/MyIndieGame/game.exe --name "My Indie Game"
|
|
runi run my-indie-game
|
|
```
|
|
|
|
Exe path validated, `game.id = my-indie-game` (unique slug),
|
|
`identity.umu_gameid = umu-default` (shared fallback, no game-specific fixes — expected for an
|
|
unknown title). `run` resolves backend=umu (the global default), builds
|
|
`PROTONPATH`/`WINEPREFIX`/`GAMEID=umu-default`, execs `umu-run`. First launch
|
|
creates the Wine prefix.
|
|
|
|
## 3. Add a second build of a game you already have
|
|
|
|
Keeping two builds installed at once — a working one and a newer one you want
|
|
to test — is a normal thing to do. Both derive the same id, so Runi
|
|
resolves it instead of overwriting:
|
|
|
|
```
|
|
runi add ~/Games/Mortal.Shell.II.v92120-P2P/.../MortalShell2-Win64-Shipping.exe \
|
|
--name "Mortal Shell II"
|
|
|
|
added mortal-shell-ii-cl92120 (Mortal Shell II)
|
|
note: a different copy of 'Mortal Shell II' is already registered as
|
|
mortal-shell-ii; this one is registered alongside it (build version cl92120,
|
|
from pe-file-version)
|
|
shared with the other copy: game identity, notes, artwork
|
|
kept separate: Wine prefix, settings, environment, logs, save backups, mod receipts
|
|
```
|
|
|
|
The suffix is the build version read from the executable, so the id says which
|
|
copy it is. When the two copies report the same version — common for engines
|
|
that stamp their own version rather than the game's — there is nothing to tell
|
|
them apart and Runi asks instead of guessing:
|
|
|
|
```
|
|
Error: 'Ascend to ZERO' is already registered as ascend-to-zero and no build
|
|
version tells the two copies apart; re-run with --id <unique-id> to add it as a
|
|
separate installation
|
|
```
|
|
|
|
In the GUI this is one dialog with the proposed id pre-filled and editable,
|
|
showing the raw version string it came from.
|
|
|
|
**If you moved or renamed the folder instead**, that is not a second copy —
|
|
Runi recognises the installation by the marker inside it and offers to
|
|
repoint the existing registration, keeping its prefix, saves, settings and
|
|
mods:
|
|
|
|
```
|
|
Error: this installation is already registered as 'Mortal Shell II'
|
|
(mortal-shell-ii); it appears to have moved
|
|
```
|
|
|
|
## 4. Add a Steam game with a different Proton version than Steam's own choice
|
|
|
|
```
|
|
runi steam-scan
|
|
runi add --steam-appid 292030 --backend native --proton GE-Proton9-27
|
|
```
|
|
|
|
`steam-scan` lists installed titles with their AppIDs. `add --steam-appid`
|
|
resolves title/exe path automatically from the scan (no manual path-typing),
|
|
sets `game.id = steam-292030`, `identity.steam_appid = 292030`, and
|
|
`identity.umu_gameid = umu-292030` (so
|
|
protonfixes still key correctly even though this game runs outside Steam's
|
|
own launch path). `runi versions` would have already flagged
|
|
`GE-Proton9-27` as safe for `native` (no `⚠ needs steamrt`), so `add` doesn't
|
|
need to warn here.
|
|
|
|
In the GUI, Runtime separates **Launch Engine** from **Runner family** and
|
|
**Version**. UMU Automatic selects the newest installed GE-Proton; Direct
|
|
Proton selects an explicit installed build.
|
|
|
|
Manual game creation asks for the executable and suggests Display Name from a
|
|
local Steam manifest, PE ProductName/FileDescription, a cleaned installation
|
|
folder or finally the executable filename. The player may edit the suggestion.
|
|
Runi then resolves Steam/UMU identity in the background from a
|
|
game-provided `steam_appid.txt`, corroborated AppID metadata in bounded local
|
|
INI files, an exact local Steam manifest match, or an exact Steam Store title
|
|
match. Local AppIDs are validated directly through Steam app details, so an
|
|
imperfect folder title does not prevent identification. Ambiguous matches
|
|
require confirmation; unavailable or failed validation leaves `umu-default`. Runtime shows the
|
|
canonical title, source, confidence and validation timestamp, retains editable
|
|
technical fields and offers explicit revalidation.
|
|
Settings → Runners manages GE-Proton, UMU-Proton, Proton-CachyOS and experimental
|
|
Proton-EM releases. Proton Experimental is detected but remains Steam-managed.
|
|
Installed versions show manager and usage badges. Selecting a games badge
|
|
expands the titles configured to use that exact version; removal remains
|
|
disabled until those games are moved to another Runtime version.
|
|
Selecting an already installed release changes the action to **Installed**.
|
|
New builds are installed transactionally, so Runi never extracts over an
|
|
existing runner or exposes a partially extracted build to Steam/UMU.
|
|
|
|
### Add from Dolphin
|
|
|
|
On KDE Plasma, enable **Settings → Desktop Integration → Show “Add to
|
|
Runi” in Dolphin**. Right-click one local Windows `.exe` and choose
|
|
**Add to Runi**. Dolphin sends the path to the already-running GUI, or
|
|
starts it when necessary, and the normal Add Game review opens.
|
|
|
|
The local candidate check is shared by Dolphin, the GUI and `runi add`.
|
|
Malformed files and DLLs are blocked. A valid PE whose role is unclear, or a
|
|
file that resembles a settings/installer utility, is shown with evidence and
|
|
ranked alternatives but may still be added deliberately. Selecting a game
|
|
already in the library focuses its existing card instead of creating a
|
|
duplicate. Requests received while a game or modal task is active remain in a
|
|
small in-memory queue.
|
|
|
|
The same entry point is available for desktop integration testing:
|
|
|
|
```bash
|
|
runi gui --add-file /path/to/game.exe
|
|
runi desktop-integration dolphin status
|
|
runi desktop-integration dolphin install
|
|
runi desktop-integration dolphin remove
|
|
```
|
|
|
|
## 5. Add a GOG/Epic title
|
|
|
|
```
|
|
runi add ~/Games/SomeGogGame/game.exe --store gog --name "Some Game"
|
|
```
|
|
|
|
Manual registration in v1 (no Heroic/Legendary auto-scan yet — see
|
|
roadmap.md (source repository)); `STORE=gog` is still forwarded so protonfixes keyed
|
|
by store apply if the umu-database has an entry for it.
|
|
|
|
## 6. Add games from Ubisoft Connect
|
|
|
|
In the GUI choose **+ → Ubisoft Connect**. Install the client automatically or
|
|
import an existing Ubisoft prefix, open it to log in/install games, then close
|
|
it. Review the locally detected titles and import the selected ones. Later,
|
|
**Play** sends the Ubisoft deeplink directly; **Tools → Stores** reopens client
|
|
management. See [ubisoft-connect.md](ubisoft-connect.md) for the shared-prefix,
|
|
runner, process-monitoring and cloud-sync rules.
|
|
|
|
## 7. Tweak display settings on a stuttery game
|
|
|
|
```
|
|
runi config steam-292030 \
|
|
--set gamescope.enabled=true \
|
|
--set gamescope.output_width=2560 --set gamescope.output_height=1440 \
|
|
--set gamescope.render_width=1920 --set gamescope.render_height=1080 \
|
|
--set gamescope.filter=fsr \
|
|
--set mangohud.enabled=true
|
|
|
|
runi run steam-292030 --dry-run
|
|
```
|
|
|
|
`--dry-run` prints the fully composed command so you can verify before
|
|
committing:
|
|
|
|
```
|
|
gamescope -W 2560 -H 1440 -w 1920 -h 1080 -F fsr --mangoapp -- umu-run witcher3.exe
|
|
```
|
|
|
|
Note MangoHud folded into gamescope's own `--mangoapp` flag rather than
|
|
becoming a separate wrapper stage (gamescope's nested compositor doesn't
|
|
support the plain MangoHud overlay). Drop `--dry-run` to launch for real.
|
|
|
|
## 8. Install OptiScaler for a game with a weak native upscaler
|
|
|
|
```
|
|
runi optiscaler install steam-292030 --dll dxgi.dll
|
|
runi run steam-292030
|
|
```
|
|
|
|
Downloads the release, backs up any `dxgi.dll` the game already shipped,
|
|
copies OptiScaler's files alongside the game exe, sets
|
|
`env.WINEDLLOVERRIDES = "dxgi=n,b"` and `[optiscaler]` state in the config.
|
|
`run` launches normally; in-game `Insert` opens the OptiScaler overlay to pick
|
|
an upscaler backend.
|
|
|
|
```
|
|
runi optiscaler remove steam-292030
|
|
```
|
|
|
|
Restores the original file from the recorded manifest and clears the env
|
|
override.
|
|
|
|
## 9. Manage Proton versions over time
|
|
|
|
```
|
|
runi versions install ge-proton latest
|
|
runi versions remove GE-Proton9-20
|
|
```
|
|
|
|
The second command fails with `VersionInUseError` listing which games still
|
|
reference that version; re-point those games first
|
|
(`runi config <id> --set runtime.proton=GE-Proton9-27`), then removal
|
|
succeeds.
|
|
|
|
## 10. Clean up
|
|
|
|
```
|
|
runi remove my-indie-game
|
|
```
|
|
|
|
The CLI deletes the registration and its Wine prefix by default; pass
|
|
`--keep-prefix` to preserve the prefix. In the GUI, removing only the
|
|
registration is the safe default. A separate checkbox can permanently delete
|
|
the marked game installation and its prefix, and warns that local saves and
|
|
settings stored in either location are also deleted. Runi refuses this
|
|
disk deletion when the installation ownership marker does not match. The
|
|
originally selected folder remains the deletion unit even when the executable
|
|
is nested deeply; recognized Unreal packages include the sibling `Engine`
|
|
directory rather than only `Binaries/Win64`. Existing Runi save backups
|
|
are kept.
|
|
|
|
For Ubisoft games, the shared prefix is always preserved. The GUI can open
|
|
Ubisoft Connect's own uninstall confirmation before removing the Runi
|
|
registration; it never deletes the Ubisoft game directory itself.
|
|
|
|
## 11. Recipes, and what replaced them
|
|
|
|
**There is no Recipe tab, and adding a game no longer offers one.** Recipes
|
|
asked the player to assemble a setup from required items, recommended items,
|
|
supplied asset files and a review step - which is a great deal of deciding for
|
|
someone who wanted to press Play. The OptiScaler tab now narrows the same
|
|
ground to two explicit choices with automatic selection between them, so the
|
|
flow that used to live here is [flow 8](#8-install-optiscaler-for-a-game-with-a-weak-native-upscaler).
|
|
|
|
What remains is rollback. A game that had a recipe applied *before* the
|
|
retirement still carries its receipt, and shows a **Recipe (Legacy)** entry
|
|
for as long as that receipt exists, so the transaction can still be reverted.
|
|
Nothing creates a new one.
|
|
|
|
For an upscaler build with no official source to automate - a leaked FSR
|
|
package, a DLSS/XeSS swap - the supported path is a customize profile, which
|
|
is [flow 13](#13-apply-a-community-upscaler-workaround-manually-advanced).
|
|
|
|
## 12. Known launch compatibility
|
|
|
|
When Runi recognises an exact canonical game with a verified launch
|
|
workaround, it applies the safe default during registration or before launch
|
|
and shows a short notification. Explicit user launch options take precedence.
|
|
|
|
The first verified case is Pathogenic's Windows build on Linux: its Godot 4.7
|
|
D3D12 path crashed in RADV while creating a VKD3D compute pipeline, while the
|
|
same executable ran correctly with `--rendering-driver vulkan`. This argument
|
|
is scoped to Pathogenic's PGID; it is not inferred for other Godot games.
|
|
|
|
## 13. Apply a community upscaler workaround manually (advanced)
|
|
|
|
Real example, validated end-to-end: enabling a leaked FSR 4.1.1 INT8 build
|
|
on non-RDNA4 hardware, for a game with OptiScaler already installed.
|
|
|
|
```
|
|
runi optiscaler install my-game --dll dxgi.dll
|
|
```
|
|
|
|
Write `~/.config/runi/profiles/fsr411-workaround.toml` once (see
|
|
[customize-profiles.md](customize-profiles.md) for the full format):
|
|
|
|
```toml
|
|
[profile]
|
|
name = "fsr411-workaround"
|
|
description = "Community FSR 4.1.1 INT8 workaround for non-RDNA4 GPUs"
|
|
|
|
[[files]]
|
|
src = "/home/user/Downloads/FidelityFX-Samples-v2.3.0-prebuilt/.../amd_fidelityfx_upscaler_dx12.dll"
|
|
dest = "amd_fidelityfx_upscaler_dx12.dll"
|
|
|
|
[[ini_edits]]
|
|
file = "OptiScaler.ini"
|
|
[ini_edits.set]
|
|
Fsr4Update = "true"
|
|
```
|
|
|
|
```
|
|
runi customize apply my-game fsr411-workaround
|
|
runi run my-game
|
|
```
|
|
|
|
In-game, press `Insert` for the OptiScaler overlay and select FSR4 → the
|
|
INT8 model. If a newer leaked build shows up later, just edit the profile's
|
|
`[[files]]` source paths and re-`apply` — the previous version is reverted
|
|
automatically before the new one is applied.
|
|
|
|
```
|
|
runi customize remove my-game
|
|
```
|
|
|
|
Restores the pre-customize state exactly (the stock OptiScaler files,
|
|
`Fsr4Update` back to its original value) — OptiScaler itself stays installed.
|
|
|
|
## 14. Enable LinUwUx for a Reflex/DenuvOwO-protected game
|
|
|
|
```
|
|
runi config my-game --set linuwux.enabled=true
|
|
runi run my-game --dry-run
|
|
```
|
|
|
|
`--dry-run` confirms the wrapper is in place:
|
|
|
|
```
|
|
linuwux umu-run MyGame.exe
|
|
```
|
|
|
|
Drop `--dry-run` to launch for real. If the Technology Scan (GUI Overview
|
|
tab, or `runi doctor`) already flagged a "Compat Shim: LinUwUx (Reflex)"
|
|
or "LinUwUx (DenuvOwO)" finding for this game, that's an informational hint
|
|
only — Runi never enables the wrapper automatically.
|
|
|
|
`[linuwux].debug=true` adds `LINUWUX_DEBUG=1` for troubleshooting; leave it
|
|
off for normal play, since it produces heavy `sigsys redirect` logging.
|
|
|
|
`[linuwux].enabled` cannot be combined with `[gamescope].enabled` —
|
|
confirmed crashing on real hardware (the gamescope session dies before the
|
|
game process ever starts), not just untested. `runi run`/`--dry-run`
|
|
refuse with `IncompatibleWrapperError` up front rather than launching into a
|
|
crash; disable gamescope first if you need linuwux.
|
|
|
|
`[mangohud].enabled` works fine alongside linuwux — Runi activates it
|
|
with `MANGOHUD=1` alone instead of mangohud's usual `LD_PRELOAD` wrapper
|
|
(which does collide), confirmed working on real hardware. No extra
|
|
configuration needed; just enable both.
|
|
|
|
If you want a custom MangoHud layout via `[mangohud].config_file`, MangoHud's
|
|
own `core_load` option (per-core CPU load/frequency) is worth knowing about:
|
|
bisected on real hardware (Monster Hunter Wilds) that enabling `core_load`
|
|
forces MangoHud back to a vertical layout even with `horizontal` set - a
|
|
per-core breakdown doesn't fit a horizontal row. Every other stat option
|
|
(`cpu_stats`, `gpu_stats`, `ram`, `vram`, `frame_timing`, etc.) composes fine
|
|
with `horizontal`; only `core_load` is the exception. This is MangoHud's own
|
|
behavior, unrelated to Runi or linuwux specifically.
|
|
|
|
That exact layout ships as a bundled preset - see flow 15 below - so you
|
|
don't have to rebuild it by hand:
|
|
`runi mangohud-preset apply horizontal-complete <id>`.
|
|
|
|
LinUwUx upstream documents only GE-Proton and Proton-CachyOS as supported
|
|
(official Valve Proton is not). If `[runtime].proton` resolves to anything
|
|
else, `runi doctor` surfaces a non-blocking advisory finding rather
|
|
than refusing to launch:
|
|
|
|
```
|
|
runi doctor
|
|
```
|
|
|
|
Requires `linuwux` to already be on `PATH` (installed via upstream's own
|
|
`install.sh`/`build.sh --install` — see
|
|
[github.com/brcly/linuwux-runtime](https://github.com/brcly/linuwux-runtime));
|
|
Runi never installs or manages it.
|
|
|
|
## 15. Save and apply a named MangoHud preset
|
|
|
|
```
|
|
runi mangohud-preset list
|
|
```
|
|
|
|
Shows every available preset — bundled (shipped with Runi) plus any
|
|
you've saved locally. Runi ships one bundled preset out of the box,
|
|
`horizontal-complete`, the exact layout validated in flow 14 above:
|
|
|
|
```
|
|
runi mangohud-preset apply horizontal-complete my-game
|
|
runi config my-game --set mangohud.enabled=true
|
|
```
|
|
|
|
This writes the preset's content to a per-game file
|
|
(`~/.local/share/runi/mangohud/<id>.conf`) and sets
|
|
`[mangohud].config_file` to it — the same effect as building the file by
|
|
hand and pointing `config_file` at it, just one command. `runi run
|
|
my-game --dry-run` shows the resolved `MANGOHUD_CONFIGFILE` to confirm.
|
|
|
|
To save your own config (built by hand, or already applied to a game you're
|
|
happy with) as a reusable preset:
|
|
|
|
```
|
|
runi mangohud-preset save my-layout --from-game my-game --description "my favorite layout"
|
|
# or, from an arbitrary file:
|
|
runi mangohud-preset save my-layout --from-file ~/some/MangoHud.conf
|
|
```
|
|
|
|
Saved presets are plain TOML at
|
|
`~/.config/runi/mangohud-presets/<name>.toml`; a local preset with the
|
|
same name as a bundled one takes priority, so you can override
|
|
`horizontal-complete` itself by saving your own version under that name.
|
|
|
|
```
|
|
runi mangohud-preset remove my-game
|
|
```
|
|
|
|
Clears `[mangohud].config_file` (falling back to MangoHud's own default
|
|
resolution order) and deletes the applied per-game file.
|
|
|
|
**Deliberately per-game only** — there is no "apply globally" (writing
|
|
`~/.config/MangoHud/MangoHud.conf`). That file is commonly managed by
|
|
third-party tools like GOverlay/MangoJuice; a second tool silently writing
|
|
over it (even with a backup taken first) creates an ongoing "who owns this
|
|
file" conflict with no clean resolution, confirmed real on a machine already
|
|
running MangoJuice. If you want a preset's layout system-wide, apply it to
|
|
each game you care about, or use GOverlay/MangoJuice's own global-config
|
|
tooling directly.
|
|
|
|
## 16. Import a Ludusavi save backup into a game's prefix
|
|
|
|
CLI-only, low-key utility — reads a [Ludusavi](https://github.com/mtkennerly/ludusavi)
|
|
backup folder (`mapping.yaml` + `drive-C/`, the "simple" non-zip format)
|
|
directly and copies the files into the game's own Wine prefix. No
|
|
dependency on the `ludusavi` binary itself.
|
|
|
|
```
|
|
runi saves import-ludusavi my-game /path/to/ludusavi/backups/My\ Game --preview
|
|
```
|
|
|
|
`--preview` shows exactly what would be copied — source → destination →
|
|
size — without writing anything. The prefix must already exist (launch the
|
|
game for real at least once first); otherwise this refuses rather than
|
|
half-creating one.
|
|
|
|
```
|
|
runi saves import-ludusavi my-game /path/to/ludusavi/backups/My\ Game
|
|
```
|
|
|
|
Copies every recorded file, verifying each one's SHA1 against what
|
|
`mapping.yaml` recorded (catches SMB/network corruption, not just logic
|
|
bugs), and — unless `--no-set-save-path` is passed — updates
|
|
`[saves].path` to the backup's own save location, so Runi's own
|
|
`saves backup`/`restore` also point at the right place afterward. If the
|
|
computed destination already has files in it, the *current* state is
|
|
backed up first via the normal `saves backup` mechanism, so an import is
|
|
always reversible.
|
|
|
|
Two real things this surfaced, worth knowing if a result looks surprising:
|
|
|
|
- **Path casing and shared folders.** Ludusavi records the source Windows
|
|
machine's own path casing (`Users`, capitalized) and username segment
|
|
(e.g. `Users/cvarandas/...`). Wine's real prefix directory is lowercase
|
|
(`users`) with its own account name (`steamuser` in every
|
|
runi-managed prefix) — a blind copy would create a bogus sibling
|
|
directory the game never sees. The importer resolves both against what's
|
|
actually on disk. It also knows `Users/Public/...` is a real, shared
|
|
folder, not a personal account to remap — confirmed by a real game (The
|
|
Sinking City 2) whose save data legitimately lives partly under `Public`.
|
|
- **A RUNE/crack config's declared save path and a Ludusavi backup's
|
|
actual files can legitimately disagree.** The Sinking City 2's RUNE
|
|
crack (`steam_emu.ini`) declares saves at
|
|
`users/Public/Documents/Steam/RUNE/2825860` — that's likely where RUNE
|
|
stores its *own* Steam-emulation state (fake achievements/cloud markers),
|
|
not necessarily the engine's native save files, which for this game
|
|
turned out to be `AppData/Local/TSC2/Saved` (confirmed by both the real
|
|
backup content and an actual game launch). The importer prints a note
|
|
when this happens (reusing Runi's existing RUNE detection as a
|
|
cross-check) but always imports to where the backup's files really are.
|
|
|
|
**Runi cannot verify a backup matches the installed game's specific
|
|
version/release** — Ludusavi's `mapping.yaml` records hashes for the save
|
|
data itself, not the source machine's game build. The safety backup above
|
|
is the actual mitigation; confirm compatibility the same way it was
|
|
confirmed here — launch the game and check.
|
|
|
|
Only the simple (non-zip) backup format is supported; a zip-format backup
|
|
folder is refused with a clear error rather than silently mishandled.
|