diff --git a/scripts/setup-kyber-linux.sh b/scripts/setup-kyber-linux.sh new file mode 100755 index 0000000..78c0b1b --- /dev/null +++ b/scripts/setup-kyber-linux.sh @@ -0,0 +1,335 @@ +#!/bin/bash +# setup-kyber-linux.sh — Install the Kyber Launcher for SWBF2 (2017) on a +# native Linux Steam machine (headless or desktop) with Proton Experimental. +# +# Kyber is a community multiplayer client for Star Wars Battlefront II (2017) +# after EA shut down the official servers. It is a Windows app (Flutter/Rust) +# with an embedded Microsoft Edge WebView2 used for its EA OAuth login flow. +# +# ── Why this is the RIGHT place to run Kyber ─────────────────────────────── +# +# Kyber's login redirects to a qrc:// URI (a Qt-internal resource scheme) that +# only its OWN embedded WebView2 can intercept. WebView2 therefore MUST work. +# +# Inside a Wolf / Games-on-Whales Docker container, WebView2 cannot start: +# Proton wraps Wine in bubblewrap (bwrap), and nesting that inside Docker +# blocks CLONE_NEWUSER, which WebView2's subprocess sandbox requires. The +# result is endless login failures (see setup-kyber-wolf.sh for the gory +# details and the fake-cmd.exe / Firefox workarounds that still cannot finish +# the flow because no external browser can handle qrc://). +# +# On NATIVE Linux Steam there is only a single bwrap layer (Proton's own), +# which has enough namespace privilege for WebView2 to initialize. So here the +# login flow works as designed: Kyber opens its built-in browser, you log in +# to EA, EA redirects to qrc://, and Kyber's WebView2 catches the auth code. +# +# No fake cmd.exe. No Firefox. No URL watcher. None of that scaffolding is +# needed here — it only existed to work around WebView2 being unable to start. +# +# ── Do you still need WebView2? YES ──────────────────────────────────────── +# +# WebView2 is not the problem — it is the solution. It is the only component +# that can complete Kyber's EA OAuth login. This script makes sure the +# WebView2 Evergreen RUNTIME (not just the bootstrapper stub) is actually +# installed in Kyber's Wine prefix. If only the stub is present, Kyber falls +# back to `cmd /c start ` and login fails even on native Linux. +# +# ── Headless note ────────────────────────────────────────────────────────── +# +# On a headless GPU box you do not need Wolf to stream. Use Steam Remote Play: +# install Steam, set up a virtual display so Steam has something to render to, +# add Kyber + SWBF2, then connect with the Steam Link app from any device. +# This script sets up a dummy/virtual X display if no display is detected. +# +# ── Prerequisites ────────────────────────────────────────────────────────── +# a. Steam installed and launched at least once (native, not Flatpak ideally +# — Flatpak works but paths differ; this script handles both). +# b. SWBF2 (AppID 1237950) installed and working with Proton Experimental +# (run setup-swbf2-linux.sh first). +# c. KyberLauncher.exe downloaded from https://kyber.gg saved to +# ~/Downloads/KyberLauncher.exe (or pass the path as $1). +# +# ── Usage ────────────────────────────────────────────────────────────────── +# chmod +x setup-kyber-linux.sh +# ./setup-kyber-linux.sh [/path/to/KyberLauncher.exe] + +set -euo pipefail + +KYBER_INSTALLER="${1:-$HOME/Downloads/KyberLauncher.exe}" +KYBER_COMPAT_ID="kyber" # Wine prefix name under compatdata/ +KYBER_APPID="9900000001" # non-Steam shortcut appid + +echo "=== Kyber Launcher — Native Linux Steam Setup ===" +echo "" + +# ── Locate Steam home ────────────────────────────────────────────────────── +find_steam_home() { + for candidate in \ + "$HOME/.steam/steam" \ + "$HOME/.local/share/Steam" \ + "$HOME/.var/app/com.valvesoftware.Steam/.steam/steam"; do + if [ -d "$candidate/steamapps" ]; then + echo "$candidate" + return 0 + fi + done + return 1 +} + +STEAM_HOME=$(find_steam_home) || { + echo "ERROR: Steam home not found. Install Steam and launch it once." + exit 1 +} +echo "Steam home: $STEAM_HOME" + +# ── Verify Kyber installer ───────────────────────────────────────────────── +if [ ! -f "$KYBER_INSTALLER" ]; then + echo "" + echo "ERROR: Kyber installer not found at: $KYBER_INSTALLER" + echo "" + echo "Download KyberLauncher.exe from https://kyber.gg, then:" + echo " $0 /path/to/KyberLauncher.exe" + exit 1 +fi +echo "Kyber installer: $KYBER_INSTALLER" + +# ── Locate Proton Experimental ───────────────────────────────────────────── +# Kyber's WebView2 is best supported on Proton Experimental (newest Wine + +# the most complete WebView2/Edge compatibility shims). GE-Proton also works, +# but Experimental tends to have the freshest fixes for Chromium sandboxing. +PROTON_DIR=$(find "$STEAM_HOME/steamapps/common" -maxdepth 1 -type d \ + -iname "Proton Experimental" 2>/dev/null | head -1) +if [ -z "$PROTON_DIR" ]; then + PROTON_DIR=$(find "$STEAM_HOME/steamapps/common" -maxdepth 1 -type d \ + -iname "Proton*" 2>/dev/null | sort | tail -1) +fi +if [ -z "$PROTON_DIR" ] || [ ! -x "$PROTON_DIR/proton" ]; then + echo "" + echo "ERROR: Proton not found under $STEAM_HOME/steamapps/common." + echo " In Steam → Settings → Compatibility, install Proton Experimental," + echo " then re-run this script." + exit 1 +fi +echo "Proton: $PROTON_DIR" + +# ── Headless display check ───────────────────────────────────────────────── +# WebView2 (and Kyber's Flutter UI) need a display to render to. On a headless +# box with no X/Wayland session, Kyber's window has nowhere to draw. +if [ -z "${DISPLAY:-}" ] && [ -z "${WAYLAND_DISPLAY:-}" ]; then + echo "" + echo "NOTE: No DISPLAY or WAYLAND_DISPLAY detected (headless box)." + echo " For Steam Remote Play you need a virtual display so Steam can" + echo " render. Options:" + echo " - Configure your GPU driver's dummy/virtual display (recommended" + echo " for hardware-encoded Remote Play), OR" + echo " - Run this whole setup under Xvfb for the install step only:" + echo " xvfb-run -a $0 $KYBER_INSTALLER" + echo "" + echo " Continuing the install (the prefix can be built headless), but you" + echo " must have a real or virtual display when you actually launch Kyber." + echo "" +fi + +# ── Build Kyber Wine prefix and run the installer ────────────────────────── +echo "" +echo "[1/5] Creating Kyber Wine prefix and running the installer..." + +KYBER_PFX="$STEAM_HOME/steamapps/compatdata/$KYBER_COMPAT_ID" +mkdir -p "$KYBER_PFX" + +export STEAM_COMPAT_DATA_PATH="$KYBER_PFX" +export STEAM_COMPAT_CLIENT_INSTALL_PATH="$STEAM_HOME" +export PROTON_NO_ESYNC=1 + +# /S runs most NSIS/Inno installers silently. If Kyber's installer ignores it, +# a GUI installer window appears — complete it normally (needs a display). +"$PROTON_DIR/proton" run "$KYBER_INSTALLER" /S || \ + "$PROTON_DIR/proton" run "$KYBER_INSTALLER" || true + +sleep 3 + +KYBER_EXE_PATH=$(find "$KYBER_PFX/pfx" -name "Kyber.exe" 2>/dev/null | head -1) +if [ -z "$KYBER_EXE_PATH" ]; then + echo "" + echo "WARNING: Kyber.exe not found after installation." + echo " If a GUI installer appeared, make sure you completed it." + echo " Default install path assumed; continuing." + KYBER_EXE_WIN='C:\Program Files\Kyber\Kyber.exe' + KYBER_START_DIR='C:\Program Files\Kyber\' +else + echo " Kyber.exe: $KYBER_EXE_PATH" + rel=$(echo "$KYBER_EXE_PATH" | sed "s|.*/pfx/drive_c/||") + KYBER_EXE_WIN="C:\\$(echo "$rel" | sed 's|/|\\|g')" + dir_rel=$(dirname "$rel") + KYBER_START_DIR="C:\\$(echo "$dir_rel" | sed 's|/|\\|g')\\" +fi +echo " Windows path: $KYBER_EXE_WIN" + +# ── Ensure WebView2 Evergreen runtime is installed ───────────────────────── +echo "" +echo "[2/5] Verifying WebView2 runtime in the Kyber prefix..." + +# The Evergreen runtime lives under one of these in the prefix once installed. +WV2_FOUND=$(find "$KYBER_PFX/pfx/drive_c" -iname "msedgewebview2.exe" 2>/dev/null | head -1) +if [ -n "$WV2_FOUND" ]; then + echo " WebView2 runtime present:" + echo " $WV2_FOUND" +else + echo " WebView2 runtime NOT found — installing Evergreen bootstrapper..." + WV2_BOOT="/tmp/MicrosoftEdgeWebview2Setup_$$.exe" + # Microsoft Evergreen Standalone/Bootstrapper installer (stable channel) + WV2_URL="https://go.microsoft.com/fwlink/p/?LinkId=2124703" + if curl -L --progress-bar -o "$WV2_BOOT" "$WV2_URL"; then + # /silent /install performs an unattended Evergreen runtime install. + "$PROTON_DIR/proton" run "$WV2_BOOT" /silent /install || true + rm -f "$WV2_BOOT" + sleep 3 + WV2_FOUND=$(find "$KYBER_PFX/pfx/drive_c" -iname "msedgewebview2.exe" 2>/dev/null | head -1) + if [ -n "$WV2_FOUND" ]; then + echo " WebView2 runtime installed:" + echo " $WV2_FOUND" + else + echo " WARNING: WebView2 install did not produce msedgewebview2.exe." + echo " Kyber may fall back to cmd /c start and fail to log in." + echo " Try installing it manually:" + echo " STEAM_COMPAT_DATA_PATH=$KYBER_PFX \\" + echo " STEAM_COMPAT_CLIENT_INSTALL_PATH=$STEAM_HOME \\" + echo " \"$PROTON_DIR/proton\" run MicrosoftEdgeWebview2Setup.exe /silent /install" + fi + else + echo " WARNING: Could not download WebView2 bootstrapper." + echo " Kyber bundles it too — its installer may have already placed it." + fi +fi + +# ── Add Kyber as a non-Steam shortcut ────────────────────────────────────── +echo "" +echo "[3/5] Adding Kyber as a non-Steam shortcut..." + +STEAM_UID=$(ls "$STEAM_HOME/userdata/" 2>/dev/null | grep -E '^[0-9]+$' | head -1) +if [ -z "$STEAM_UID" ]; then + echo " WARNING: No Steam userdata found — sign in to Steam once, then re-run." + echo " Skipping shortcut + compat mapping." + SKIP_STEAM_CFG=1 +else + SHORTCUTS_DIR="$STEAM_HOME/userdata/$STEAM_UID/config" + SHORTCUTS_FILE="$SHORTCUTS_DIR/shortcuts.vdf" + mkdir -p "$SHORTCUTS_DIR" + [ -f "$SHORTCUTS_FILE" ] && cp "$SHORTCUTS_FILE" "$SHORTCUTS_FILE.bak" + + python3 - "$SHORTCUTS_FILE" "$KYBER_APPID" "$KYBER_EXE_WIN" "$KYBER_START_DIR" << 'PYEOF' +import sys, struct, os + +def s(key, value): # VDF string field + return b'\x01' + key.encode() + b'\x00' + value.encode() + b'\x00' +def i(key, value): # VDF int field + return b'\x02' + key.encode() + b'\x00' + struct.pack('