docs: user-facing documentation and signing key
This commit is contained in:
@@ -0,0 +1,475 @@
|
||||
<!-- 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.
|
||||
Reference in New Issue
Block a user