mirror of
https://github.com/ryan4yin/nix-config.git
synced 2026-11-13 12:13:36 +01:00
185 lines
6.5 KiB
Nu
185 lines
6.5 KiB
Nu
#!/usr/bin/env nu
|
|
#
|
|
# Install a Windows game launcher into its own umu-launcher Wine prefix, and
|
|
# generate launch/exec/desktop/uninstall helpers for it.
|
|
#
|
|
# umu-launcher is the Proton backend Lutris/Heroic use: it creates and runs a
|
|
# detached Wine prefix without Steam, and a GAMEID from the umu database pulls
|
|
# in that game's protonfixes (fonts, env quirks, save location, ...). This
|
|
# installer is fully generic -- it knows no game names. Every per-game detail
|
|
# lives under ~/Games/<name>/:
|
|
#
|
|
# prefix the Wine prefix (WINEPREFIX)
|
|
# prelaunch optional executable, run before every launch
|
|
# conf optional shell file overriding the generated defaults
|
|
# run generated launcher
|
|
# exec generated helper: run any exe/wine tool in the prefix
|
|
# <name>.desktop generated desktop entry
|
|
# uninstall generated: drop the desktop entry and (with confirmation) this dir
|
|
#
|
|
# ~/Games/global.conf, if present, is sourced by every run script before the
|
|
# game's own conf; both may set ENABLE_GAMEMODE, ENABLE_GAMESCOPE,
|
|
# GAMESCOPE_ARGS, ENABLE_LOG, PROTONPATH, GAMEID, LAUNCHER, ...
|
|
#
|
|
# PROTONPATH is resolved from $PROTONPATH, then $UMU_PROTONPATH (exported by
|
|
# modules/nixos/desktop/gaming.nix from pkgs.dwproton-bin), then Steam's
|
|
# per-user compatibilitytools.d.
|
|
#
|
|
# nu .agents/skills/nix-config-umu-game/scripts/umu-install.nu wuthering-waves \
|
|
# ~/Downloads/WutheringWaves_setup_3.5.0.exe \
|
|
# "drive_c/Program Files/Wuthering Waves/launcher.exe" \
|
|
# umu-3513350
|
|
#
|
|
# Extra arguments after [gameid] are passed to the installer, e.g. "/S" or
|
|
# "/quiet" for a silent install.
|
|
|
|
def games-dir [] {
|
|
$nu.home-dir | path join "Games"
|
|
}
|
|
|
|
# First candidate that actually contains a proton script.
|
|
def resolve-protonpath [] {
|
|
let explicit = ($env.PROTONPATH? | default "")
|
|
if (not ($explicit | is-empty)) and (($explicit | path join "proton") | path exists) {
|
|
return $explicit
|
|
}
|
|
let umu = ($env.UMU_PROTONPATH? | default "")
|
|
if (not ($umu | is-empty)) and (($umu | path join "proton") | path exists) {
|
|
return $umu
|
|
}
|
|
let steam = ($nu.home-dir | path join ".local/share/Steam/compatibilitytools.d/dwproton")
|
|
if (($steam | path join "proton") | path exists) {
|
|
return $steam
|
|
}
|
|
null
|
|
}
|
|
|
|
# "wuthering-waves" -> "Wuthering Waves"
|
|
def reject-symlink [path: string, label: string] {
|
|
let kind = (try { $path | path type } catch { "missing" })
|
|
if $kind == "symlink" {
|
|
print --stderr $"error: ($label) must not be a symlink: ($path)"
|
|
exit 2
|
|
}
|
|
}
|
|
|
|
def display-name [name: string] {
|
|
$name | split row "-" | each { |w| $w | str capitalize } | str join " "
|
|
}
|
|
|
|
def usage [] {
|
|
print "Usage: .agents/skills/nix-config-umu-game/scripts/umu-install.nu <name> <setup.exe> <launcher> [gameid] [setup-args...]"
|
|
print ""
|
|
print " <name> directory under ~/Games (e.g. wuthering-waves)"
|
|
print " <setup.exe> installer to run through umu (a host path)"
|
|
print " <launcher> launcher to run later, relative to the prefix"
|
|
print " [gameid] umu database id for protonfixes (default umu-default)"
|
|
print " [setup-args] extra args for setup.exe, e.g. /S or /quiet"
|
|
print ""
|
|
print "Writes ~/Games/<name>/{run,exec,<name>.desktop,uninstall}. A per-game"
|
|
print "fix goes in ~/Games/<name>/prelaunch; overrides go in ~/Games/<name>/conf"
|
|
print "or ~/Games/global.conf. PROTONPATH comes from $PROTONPATH or"
|
|
print "$UMU_PROTONPATH."
|
|
}
|
|
|
|
# Quote substituted shell values as data, including literal apostrophes.
|
|
def shell-quote [value: string] {
|
|
"'" + ($value | str replace --all "'" "'\\''") + "'"
|
|
}
|
|
|
|
def render-template [name: string, values: record] {
|
|
let template = ($env.FILE_PWD | path join "templates" $name)
|
|
open --raw $template | str replace --all --regex '@([A-Z_]+)@' { |key|
|
|
$values | get $key
|
|
}
|
|
}
|
|
|
|
def write-run [name: string, launcher: string] {
|
|
let dir = ((games-dir) | path join $name)
|
|
let values = {
|
|
WINEPREFIX: (shell-quote $env.WINEPREFIX)
|
|
PROTONPATH: (shell-quote $env.PROTONPATH)
|
|
GAMEID: (shell-quote $env.GAMEID)
|
|
LAUNCHER: (shell-quote $launcher)
|
|
}
|
|
mkdir $dir
|
|
for file in [run exec] {
|
|
let target = ($dir | path join $file)
|
|
render-template $"($file).sh.tpl" $values | save --force $target
|
|
^chmod +x $target
|
|
}
|
|
}
|
|
|
|
def write-integration [name: string] {
|
|
let dir = ((games-dir) | path join $name)
|
|
let apps = ($nu.home-dir | path join ".local/share/applications")
|
|
let entry = ($apps | path join $"($name).desktop")
|
|
let desktop = (render-template "launcher.desktop.tpl" {
|
|
DISPLAY_NAME: (display-name $name)
|
|
RUN: ($dir | path join "run")
|
|
DIR: $dir
|
|
})
|
|
mkdir $apps
|
|
$desktop | save --force ($dir | path join $"($name).desktop")
|
|
$desktop | save --force $entry
|
|
let uninstall = ($dir | path join "uninstall")
|
|
render-template "uninstall.sh.tpl" {
|
|
DESKTOP_FILE: (shell-quote $entry)
|
|
GAMES_DIR: (shell-quote (games-dir))
|
|
NAME: (shell-quote $name)
|
|
} | save --force $uninstall
|
|
^chmod +x $uninstall
|
|
}
|
|
|
|
def main [...args: string] {
|
|
if ($args | length) < 3 {
|
|
usage
|
|
exit 1
|
|
}
|
|
let name = ($args | get 0)
|
|
if not ($name =~ '^[a-z0-9]+(-[a-z0-9]+)*$') {
|
|
print --stderr "error: name must be a lowercase slug (letters, digits, hyphens)"
|
|
exit 2
|
|
}
|
|
let setup = ($args | get 1)
|
|
let launcher = ($args | get 2)
|
|
let gameid = (if ($args | length) >= 4 { $args | get 3 } else { "umu-default" })
|
|
let setupArgs = (if ($args | length) >= 5 { $args | skip 4 } else { [] })
|
|
let root = (games-dir)
|
|
reject-symlink $root "Games directory"
|
|
let dir = ($root | path join $name)
|
|
let prefix = ($dir | path join "prefix")
|
|
reject-symlink $dir "game directory"
|
|
reject-symlink $prefix "Wine prefix"
|
|
|
|
let protonpath = (resolve-protonpath)
|
|
if $protonpath == null {
|
|
print --stderr "error: no Proton found. Set PROTONPATH or UMU_PROTONPATH, or rebuild NixOS so modules/nixos/desktop/gaming.nix exports UMU_PROTONPATH."
|
|
exit 1
|
|
}
|
|
$env.PROTONPATH = $protonpath
|
|
|
|
$env.WINEPREFIX = $prefix
|
|
$env.GAMEID = $gameid
|
|
|
|
print $"installing '($name)' into ($env.WINEPREFIX)"
|
|
print $" PROTONPATH = ($env.PROTONPATH)"
|
|
print $" GAMEID = ($env.GAMEID)"
|
|
print "run the installer, then exit it (do not start the game)."
|
|
|
|
let inst = (^umu-run $setup ...$setupArgs | complete)
|
|
if $inst.exit_code != 0 {
|
|
print --stderr $"installer exited ($inst.exit_code); writing the launchers anyway"
|
|
}
|
|
|
|
let prelaunch = ($dir | path join "prelaunch")
|
|
if ($prelaunch | path exists) {
|
|
print $"running prelaunch: ($prelaunch)"
|
|
run-external $prelaunch
|
|
}
|
|
|
|
write-run $name $launcher
|
|
write-integration $name
|
|
print $"done. launch with: ($dir)/run"
|
|
}
|