From 6b385e62ba3e2a7b39beafa1fcdbb3417be728b1 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 22 Jun 2026 04:25:26 +0000 Subject: [PATCH 1/4] docs: update SWBF2 guide with direct-exe bypass and Origin registry spoof Revised approach: skip link2ea:// and EA App account requirement entirely. Launch starwarsbattlefrontii.exe directly via the wrapper, spoof Origin registry entries so the game's built-in launcher check passes. Documents what doesn't work and why (msiexec/bwrap/EA account issues). Co-Authored-By: Claude Sonnet 4.6 Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs --- docs/SWBF2-2017-wolf-setup.md | 295 +++++++++++++++++----------------- 1 file changed, 148 insertions(+), 147 deletions(-) diff --git a/docs/SWBF2-2017-wolf-setup.md b/docs/SWBF2-2017-wolf-setup.md index 8f9ca6b..37a88f4 100644 --- a/docs/SWBF2-2017-wolf-setup.md +++ b/docs/SWBF2-2017-wolf-setup.md @@ -9,11 +9,13 @@ ## Why this is hard SWBF2 (2017) is an EA game. EA mandated their **EA App** launcher for all EA Steam titles. -On launch, SWBF2 calls `ShellExecuteW("link2ea://launchgame/1237950?platform=steam&theme=swbfii")`. -GE-Proton's `steam.exe` intercepts that URL, finds `Link2EA.exe` from the EA Desktop install, and -hands off to the EA App which then launches the actual game. +On launch, Steam passes `link2ea://launchgame/1237950?platform=steam&theme=swbfii` as the +"executable" to GE-Proton. The game binary itself also checks for Origin/EA App in the +registry before starting. -Without EA Desktop installed in the Wine prefix, the game exits immediately. +EA App requires an EA account login, and ea.com/signup has been unreliable. The workaround +here **bypasses EA App entirely**: launch the game executable directly and spoof the Origin +registry entries so the game thinks its launcher is installed. --- @@ -35,214 +37,213 @@ Only Steam itself can properly launch programs through sniper+GE-Proton. --- -## Solution: Steam launch wrapper +## Solution overview -Use SWBF2's **Steam launch options** to intercept the launch, run a helper script, -then pass control back to Steam's real launch chain. +1. Intercept the Steam launch with a wrapper script (via launch options) +2. Spoof Origin registry entries so SWBF2 thinks its launcher is present +3. Skip link2ea:// entirely — launch `starwarsbattlefrontii.exe` directly -Steam passes all its args to the wrapper as `$@`: -``` -steam-launch-wrapper -- reaper SteamLaunch AppId=1237950 -- --verb=waitforexitandrun -- waitforexitandrun -``` - -The wrapper runs msiexec (or anything else) inside the full sniper+GE-Proton environment -that Steam set up, then `exec "$@"` to hand off to the game. +No EA account needed. No EA App login needed. --- ## Step-by-step -### 1. Lock localconfig.vdf against Steam overwriting it - -Steam uses atomic rename (write temp + rename) when saving config. -`chmod 444` on the file is bypassed. Lock the **directory** instead: +### 1. Find the WolfSteam container name and Steam user ID ```bash -WOLF_CONTAINER="WolfSteam_XXXXXXXXXXXXXXXX" # docker ps to find exact name -CONFIG_DIR="/home/retro/.steam/steam/userdata/XXXXXXXXX/config" +WOLF_CONTAINER=$(docker ps --format '{{.Names}}' | grep Wolf) +echo "$WOLF_CONTAINER" -# Find container name -docker ps --format '{{.Names}}' | grep Wolf +STEAM_UID=$(docker exec "$WOLF_CONTAINER" ls /home/retro/.steam/steam/userdata/) +echo "$STEAM_UID" -# Find Steam user ID -docker exec "$WOLF_CONTAINER" ls /home/retro/.steam/steam/userdata/ +CONFIG_DIR="/home/retro/.steam/steam/userdata/$STEAM_UID/config" +``` +### 2. Lock localconfig.vdf against Steam overwriting it + +Steam uses atomic rename (write temp + rename) when saving config. +`chmod 444` on the file is bypassed by the rename. Lock the **directory** instead: + +```bash docker exec "$WOLF_CONTAINER" chmod 555 "$CONFIG_DIR" ``` -### 2. Set SWBF2 launch options +### 3. Set SWBF2 launch options in localconfig.vdf -Edit localconfig.vdf **while Steam is not running** (or kill Steam first): +Kill Steam first so it flushes and releases the file, then edit: ```bash -CONFIG_FILE="$CONFIG_DIR/localconfig.vdf" - -# Kill Steam so it flushes and stops watching docker exec "$WOLF_CONTAINER" pkill -f steam.sh || true sleep 3 -# Edit — find the LaunchOptions line for AppID 1237950 -# Add before it if missing: -docker exec "$WOLF_CONTAINER" bash -c " - sed -i '/\"1237950\"/,/}/ s/\"LaunchOptions\"\s*\"[^\"]*\"/\"LaunchOptions\"\t\t\"STEAM_UNIX_SOCKET=\/tmp\/steam.sock \/home\/retro\/ea_install.sh %command%\"/' '$CONFIG_FILE' -" -# Or if LaunchOptions key doesn't exist yet, add it manually. -# Verify: -docker exec "$WOLF_CONTAINER" grep -A5 '"1237950"' "$CONFIG_FILE" | grep LaunchOptions +CONFIG_FILE="$CONFIG_DIR/localconfig.vdf" + +# The file needs a LaunchOptions entry under AppID 1237950. +# Find the block and add/replace LaunchOptions: +docker exec "$WOLF_CONTAINER" grep -A5 '"1237950"' "$CONFIG_FILE" +# If LaunchOptions is missing, add it manually to the 1237950 block: +# "LaunchOptions" "STEAM_UNIX_SOCKET=/tmp/steam.sock /home/retro/ea_install.sh %command%" ``` -### 3. Write the EA install wrapper +The launch option value must be: +``` +STEAM_UNIX_SOCKET=/tmp/steam.sock /home/retro/ea_install.sh %command% +``` -The wrapper runs `msiexec /a` (administrative install — no custom actions) to extract -EA Desktop files, then execs the real game: +### 4. Write the Origin registry spoof + +SWBF2's binary checks for Origin in the registry before starting. Spoof it by writing +directly to Wine's system.reg (plain text file — no Wine needed): + +```bash +SYSREG="/home/retro/.steam/steam/steamapps/compatdata/1237950/pfx/system.reg" +TIMESTAMP=$(date +%s) + +docker exec "$WOLF_CONTAINER" bash -c "cat >> '$SYSREG' << 'REGEOF' + +[Software\\\\Origin] $TIMESTAMP +\"ClientPath\"=\"C:\\\\\\\\Program Files\\\\\\\\Electronic Arts\\\\\\\\EA Desktop\\\\\\\\EA Desktop\\\\\\\\EADesktop.exe\" +\"InstallDir\"=\"C:\\\\\\\\Program Files\\\\\\\\Electronic Arts\\\\\\\\EA Desktop\\\\\\\\EA Desktop\\\\\\\\\" + +[Software\\\\Wow6432Node\\\\Origin] $TIMESTAMP +\"ClientPath\"=\"C:\\\\\\\\Program Files\\\\\\\\Electronic Arts\\\\\\\\EA Desktop\\\\\\\\EA Desktop\\\\\\\\EADesktop.exe\" +\"InstallDir\"=\"C:\\\\\\\\Program Files\\\\\\\\Electronic Arts\\\\\\\\EA Desktop\\\\\\\\EA Desktop\\\\\\\\\" +REGEOF" + +# Verify +docker exec "$WOLF_CONTAINER" grep -A3 'Software\\\\Origin' "$SYSREG" +``` + +### 5. Write the launch wrapper + +The wrapper receives Steam's full launch chain as `$@` (args 1–11 are the +sniper+GE-Proton preamble, arg 12 is normally `link2ea://...`). Replace the last +arg with the actual game executable: ```bash cat > /tmp/ea_install.sh << 'EOF' #!/bin/bash -echo "=== ea_install.sh called $(date) ===" >> /tmp/ea_install.log -echo "Args: $@" >> /tmp/ea_install.log -"$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9" "${10}" "${11}" \ - msiexec /i "C:\\ea_app.msi" /qn \ - TARGETDIR="C:\\Program Files\\Electronic Arts" \ - /l*v "C:\\msi_admin.log" \ - >> /tmp/ea_install.log 2>&1 -echo "MSI exit: $?" >> /tmp/ea_install.log -exec "$@" +echo "=== launch $(date) ===" >> /tmp/ea_install.log +GAME_EXE="/home/retro/.steam/steam/steamapps/common/STAR WARS Battlefront II/starwarsbattlefrontii.exe" +exec "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9" "${10}" "${11}" "$GAME_EXE" EOF chmod +x /tmp/ea_install.sh docker cp /tmp/ea_install.sh "$WOLF_CONTAINER":/home/retro/ea_install.sh ``` -### 4. Get the EA App MSI +### 6. Launch SWBF2 in Moonlight -The MSI ships inside SWBF2's game files. Copy it into the Wine prefix: +Steam → wrapper → `starwarsbattlefrontii.exe` runs directly inside sniper+GE-Proton. +The game checks Origin registry, finds the spoofed entries, and starts. + +You may see Vulkan shader compilation prompts on first launch — these can be skipped; +the game will still proceed (shaders compile lazily or are skipped). + +### 7. Restore clean state (after confirmed working) ```bash -MSI_SRC="/home/retro/.steam/steam/steamapps/common/STAR WARS Battlefront II/__Installer/Origin/redist/internal/EAappInstaller.exe" -# EAappInstaller.exe is a WiX Burn bootstrapper — the real MSI is buried inside. -# Easier: use the MSI that gets extracted to the Wine prefix during a first launch attempt: -MSI_IN_PREFIX="/home/retro/.steam/steam/steamapps/compatdata/1237950/pfx/drive_c/ea_app.msi" +# Restore directory to writable so Steam can save normally +docker exec "$WOLF_CONTAINER" chmod 755 "$CONFIG_DIR" + +# Remove LaunchOptions for 1237950 from localconfig.vdf while Steam is stopped ``` -The MSI appears in the Wine prefix (`drive_c/ea_app.msi`, ~227 MB) after SWBF2 is launched -once — GE-Proton's protonfixes or steam.exe drops it there. +--- -### 5. Extract EA Desktop files on the host (bypassing Wine custom actions) +## Background: what Steam actually passes to the wrapper -The MSI's `JunoConfigureRegistry` custom action fails in Wine (it tries to set registry -ACLs via `SetSecurityDescriptorSddlForm` which Wine doesn't support). This causes -MSI rollback and removes all installed files. Bypass it by extracting on Linux: +``` +$1 = /path/to/steam-launch-wrapper +$2 = -- +$3 = /path/to/reaper +$4 = SteamLaunch +$5 = AppId=1237950 +$6 = -- +$7 = /path/to/SteamLinuxRuntime_sniper/_v2-entry-point +$8 = --verb=waitforexitandrun +$9 = -- +$10 = /path/to/GE-Proton10-34/proton +$11 = waitforexitandrun +$12 = link2ea://launchgame/1237950?platform=steam&theme=swbfii ← we replace this +``` +--- + +## What doesn't work (and why) + +### Running msiexec / Wine via docker exec +`docker exec` carries Linux capabilities that break bwrap. Any attempt to run +Proton/wine64 outside Steam's own launch chain gets: +``` +setting up uid map: Permission denied +``` + +### Running the EA App MSI through Wine (INST-14-1603) +The MSI's `JunoConfigureRegistry` .NET custom action uses `SetSecurityDescriptorSddlForm` +to set registry ACLs. Wine doesn't support this — the action returns 0 (failure), +causing the entire install to roll back. `DISABLEROLLBACK=1` doesn't help because +MSI logs the product as already-registered from the first attempt, causing subsequent +runs to produce an empty log and exit. + +### link2ea:// approach with EA account +EA App requires an EA account linked to your Steam account. `ea.com/signup` is +unreliable. Even with an account, EA Desktop must be installed in the Wine prefix +(see msiextract bypass below if needed). Bypassing the game exe directly is simpler. + +### msiextract bypass (if EA App files are needed for something else) +If you need EA Desktop files in the prefix for another reason: ```bash -# Copy MSI out of container +# Copy MSI out of container (appears in drive_c after first launch attempt) docker cp "$WOLF_CONTAINER:/home/retro/.steam/steam/steamapps/compatdata/1237950/pfx/drive_c/ea_app.msi" \ /tmp/ea_app.msi -# Extract (msitools package) +# Extract on host (bypasses JunoConfigureRegistry entirely) sudo apt-get install -y msitools mkdir -p /tmp/ea_app_extracted msiextract -C /tmp/ea_app_extracted /tmp/ea_app.msi -``` -### 6. Copy EA Desktop into the Wine prefix - -The MSI installs to `C:\Program Files\Electronic Arts\EA Desktop\` with a versioned -subdirectory (`14.2.0.3345`) and a symlink `EA Desktop -> 14.2.0.3345`. - -The normal MSI install creates that symlink via `JunoSetupSymlinkMode`. After a -failed install + rollback, the symlink may remain but the versioned dir is gone. - -```bash PFXBASE="/home/retro/.steam/steam/steamapps/compatdata/1237950/pfx/drive_c/Program Files/Electronic Arts/EA Desktop" - -# Remove any broken symlink docker exec "$WOLF_CONTAINER" bash -c " [ -L '$PFXBASE/EA Desktop' ] && rm '$PFXBASE/EA Desktop' mkdir -p '$PFXBASE/14.2.0.3345' ln -s 14.2.0.3345 '$PFXBASE/EA Desktop' " - -# Copy extracted files into versioned directory docker cp "/tmp/ea_app_extracted/Electronic Arts/EA Desktop/EA Desktop/." \ "$WOLF_CONTAINER:$PFXBASE/14.2.0.3345/" - -# Verify -docker exec "$WOLF_CONTAINER" find "$PFXBASE" -name "Link2EA.exe" -``` - -Expected output: -``` -/home/retro/.steam/steam/steamapps/compatdata/1237950/pfx/drive_c/Program Files/Electronic Arts/EA Desktop/14.2.0.3345/Link2EA.exe -``` - -### 7. Switch wrapper to pass-through and launch - -Once EA Desktop files are in place, update the wrapper to just exec the game: - -```bash -cat > /tmp/ea_passthrough.sh << 'EOF' -#!/bin/bash -echo "=== launch $(date) ===" >> /tmp/ea_install.log -exec "$@" -EOF -chmod +x /tmp/ea_passthrough.sh -docker cp /tmp/ea_passthrough.sh "$WOLF_CONTAINER":/home/retro/ea_install.sh -``` - -Launch SWBF2 in Moonlight. Steam → GE-Proton → SWBF2 → link2ea:// → steam.exe -finds Link2EA.exe → EA App launches → SWBF2 loads. - -### 8. EA account login (one-time) - -On first launch, EA Desktop will show a login screen. Log in with your EA account. -Credentials are cached; subsequent launches skip login. - -### 9. Restore clean state - -After EA Desktop is confirmed working, remove the launch wrapper: - -```bash -# Restore directory to writable -docker exec "$WOLF_CONTAINER" chmod 755 "$CONFIG_DIR" - -# Remove LaunchOptions from localconfig.vdf -# (edit the file while Steam is stopped, remove the LaunchOptions line for 1237950) ``` --- ## Troubleshooting -### "link2ea not found" / game exits in ~6 seconds -EA Desktop files are missing or in wrong path. Check: +### Game exits in ~6 seconds, no popup +Check wrapper log inside container: ```bash -docker exec "$WOLF_CONTAINER" find \ - "/home/retro/.steam/steam/steamapps/compatdata/1237950/pfx/drive_c/Program Files/Electronic Arts" \ - -name "Link2EA.exe" +docker exec "$WOLF_CONTAINER" bash -c " + cat /tmp/ea_install.log | tail -20 + find /home/retro/.steam/steam/steamapps/compatdata/1237950/ -name '*.log' \ + -newer /tmp/ea_install.log 2>/dev/null | xargs tail -20 2>/dev/null +" +``` + +### "Origin is not installed" popup +Origin registry entries missing. Repeat step 4 and verify: +```bash +docker exec "$WOLF_CONTAINER" grep -A3 'Software\\\\Origin' \ + '/home/retro/.steam/steam/steamapps/compatdata/1237950/pfx/system.reg' ``` ### Wrapper never runs (Steam ignores launch options) -Steam wrote config before chmod 555 was applied. Kill Steam, chmod 555 the directory, -then edit localconfig.vdf. Steam reads config fresh on startup. - -### INST-14-1603 error in EA App installer -`JunoConfigureRegistry` .NET custom action returns 0 in Wine. This is a Wine limitation -with registry ACL operations. Use the `msiextract` bypass (Step 5–6) instead of -running the MSI through Wine. - -### msiexec DISABLEROLLBACK=1 produces empty log -MSI detected a stale product registration from a previous failed install. -Check: `grep -i C2622085 /home/retro/.steam/steam/steamapps/compatdata/1237950/pfx/system.reg` -If present, delete those registry keys then retry. - -### wine64 segfaults outside Steam (exit 139) -GE-Proton10's wine64 requires the sniper runtime. Never call it directly from -`docker exec` — always use Steam's launch chain via the wrapper approach. +Steam wrote config before chmod 555 was applied. Kill Steam, verify chmod 555 is set +on the config directory, edit localconfig.vdf, then start Steam again. ### localconfig.vdf gets overwritten on Steam shutdown -Steam uses atomic rename (temp file + rename into place). `chmod 444` on the file -is bypassed by the rename. Solution: `chmod 555` on the **directory** containing -localconfig.vdf — this prevents new files being renamed into the directory. +`chmod 555` on the directory (not the file) prevents the atomic rename Steam uses. + +### wine64 segfaults outside Steam (exit 139) +GE-Proton10's wine64 requires the sniper runtime. Never call it via `docker exec`. --- @@ -251,9 +252,9 @@ localconfig.vdf — this prevents new files being renamed into the directory. | Path | Description | |------|-------------| | `/home/retro/.steam/steam/steamapps/compatdata/1237950/pfx/` | SWBF2 Wine prefix | -| `/home/retro/.steam/steam/steamapps/compatdata/1237950/pfx/drive_c/ea_app.msi` | EA App MSI (~227 MB) | -| `/home/retro/.steam/steam/steamapps/compatdata/1237950/pfx/drive_c/Program Files/Electronic Arts/EA Desktop/14.2.0.3345/` | EA Desktop files | -| `/home/retro/.steam/steam/steamapps/compatdata/1237950/pfx/drive_c/Program Files/Electronic Arts/EA Desktop/EA Desktop` | Symlink → `14.2.0.3345` | +| `/home/retro/.steam/steam/steamapps/compatdata/1237950/pfx/system.reg` | Wine HKLM registry (plain text) | +| `/home/retro/.steam/steam/steamapps/compatdata/1237950/pfx/drive_c/ea_app.msi` | EA App MSI (~227 MB, appears after first launch) | +| `/home/retro/.steam/steam/steamapps/common/STAR WARS Battlefront II/starwarsbattlefrontii.exe` | Actual game binary | | `/home/retro/.steam/steam/userdata//config/localconfig.vdf` | Steam per-user config (launch options) | | `/home/retro/ea_install.sh` | Launch wrapper script | -| `/tmp/ea_install.log` | Wrapper log (inside container) | +| `/tmp/ea_install.log` | Wrapper log (inside container, resets on container restart) | From 5cff764d3b4a900f28489a5fa2030a77d0cacd3e Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 22 Jun 2026 05:02:19 +0000 Subject: [PATCH 2/4] docs: add EA auth dependency context, login process, and longevity notes Documents the EA account requirement, first-time login flow, credential caching for machine transfers, community server options if EA shuts down, and the SWBF2 2005 alternative for a launcher-free experience. Co-Authored-By: Claude Sonnet 4.6 Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs --- docs/SWBF2-2017-wolf-setup.md | 63 +++++++++++++++++++++++++++-------- 1 file changed, 50 insertions(+), 13 deletions(-) diff --git a/docs/SWBF2-2017-wolf-setup.md b/docs/SWBF2-2017-wolf-setup.md index 37a88f4..1a21839 100644 --- a/docs/SWBF2-2017-wolf-setup.md +++ b/docs/SWBF2-2017-wolf-setup.md @@ -6,16 +6,41 @@ --- -## Why this is hard +## The EA dependency problem -SWBF2 (2017) is an EA game. EA mandated their **EA App** launcher for all EA Steam titles. -On launch, Steam passes `link2ea://launchgame/1237950?platform=steam&theme=swbfii` as the -"executable" to GE-Proton. The game binary itself also checks for Origin/EA App in the -registry before starting. +SWBF2 (2017) has a hard dependency on EA's authentication infrastructure: -EA App requires an EA account login, and ea.com/signup has been unreliable. The workaround -here **bypasses EA App entirely**: launch the game executable directly and spoof the Origin -registry entries so the game thinks its launcher is installed. +- **Steam** handles payment, library, and game files +- **EA App** handles identity and authentication — even for offline single-player + +First launch requires an internet connection and an EA account login. After that, EA App +caches credentials locally and subsequent launches work offline — but only until the token +expires or EA's servers go dark permanently. + +**What happens when EA shuts down authentication servers?** +The game becomes unplayable through legitimate means. EA has done this before (Battlefield 2, +The Sims Online, older Origin titles). For a 9-year-old game with a shrinking playerbase, +this is a real risk. + +Community options if/when that happens: +- **Private servers** — the SWBF2 community has projects like Kyber for multiplayer. If EA + kills auth, expect the community to build replacement auth servers as they did for BF2 (BF2Hub, OpenSpy). +- **Play SWBF2 (2005) instead** — the classic 2005 Battlefront II runs natively on Linux + through Proton with zero launcher requirements, no accounts, no phoning home. + AppID: 6060. It just works. + +**Backing up credentials for machine transfers:** +EA App caches credentials inside the Wine prefix. Back up the entire compatdata directory: +```bash +tar -czf swbf2-prefix-backup.tar.gz \ + /home/retro/.steam/steam/steamapps/compatdata/1237950/ +``` +Restore it on another machine and the cached login travels with it — until the token expires +(EA tokens last weeks to months). Not a permanent solution but useful for migrations. + +--- + +## Why this is hard (technically) --- @@ -133,13 +158,25 @@ chmod +x /tmp/ea_install.sh docker cp /tmp/ea_install.sh "$WOLF_CONTAINER":/home/retro/ea_install.sh ``` -### 6. Launch SWBF2 in Moonlight +### 6. Launch SWBF2 in Moonlight — first-time EA login -Steam → wrapper → `starwarsbattlefrontii.exe` runs directly inside sniper+GE-Proton. -The game checks Origin registry, finds the spoofed entries, and starts. +On first launch Steam passes `link2ea://launchgame/1237950?platform=steam&theme=swbfii` +to GE-Proton, which hands it to `Link2EA.exe`. EA App opens and shows a login screen. -You may see Vulkan shader compilation prompts on first launch — these can be skipped; -the game will still proceed (shaders compile lazily or are skipped). +**Vulkan shader compilation** appears before the game loads on first run. Let it complete +— do not skip it. It only runs once and takes several minutes. + +**EA App login:** +1. Log in with your EA account credentials +2. Check "Stay logged in" / "Remember me" — this caches the token locally +3. EA App links your Steam purchase to your EA account +4. The game launches + +**After first login**, credentials are cached in the Wine prefix at: +``` +compatdata/1237950/pfx/drive_c/users/steamuser/AppData/Local/EADesktop/ +``` +Subsequent launches skip the login screen entirely. ### 7. Restore clean state (after confirmed working) From b756e7eedb656e42a30665d6fb253a58cff2740a Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 22 Jun 2026 12:35:14 +0000 Subject: [PATCH 3/4] docs: rewrite SWBF2-2017 guide with working msiextract + wrapper solution Complete rewrite reflecting the actual working setup: - msiextract on host bypasses JunoConfigureRegistry Wine incompatibility - Wrapper script imports registry fixes via regedit through Steam's launch chain - chmod 555 on config dir prevents Steam overwriting localconfig.vdf - Honest fresh-install assessment table (what's automated vs one-time manual) - Troubleshooting section covering all errors encountered - Key paths reference table Co-Authored-By: Claude Sonnet 4.6 Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs --- docs/SWBF2-2017-wolf-setup.md | 441 ++++++++++++++++++---------------- 1 file changed, 234 insertions(+), 207 deletions(-) diff --git a/docs/SWBF2-2017-wolf-setup.md b/docs/SWBF2-2017-wolf-setup.md index 1a21839..2d80684 100644 --- a/docs/SWBF2-2017-wolf-setup.md +++ b/docs/SWBF2-2017-wolf-setup.md @@ -1,287 +1,312 @@ # Star Wars Battlefront II (2017) — Wolf/Moonlight Setup **AppID:** 1237950 -**Proton:** GE-Proton10-34 (required — stock Proton does not work with EA App) +**Proton:** GE-Proton10-34 (required) **Platform:** Wolf (Games-on-Whales) — WolfSteam Docker container --- +## Prerequisites + +- SWBF2 installed via Steam in the WolfSteam session +- GE-Proton10-34 installed (Steam → Settings → Compatibility → Enable Steam Play) +- EA account created at ea.com and linked to your Steam account +- `msitools` on the Docker host: `sudo apt-get install -y msitools` + +--- + ## The EA dependency problem -SWBF2 (2017) has a hard dependency on EA's authentication infrastructure: +SWBF2 (2017) requires EA's launcher infrastructure — even for single-player offline: - **Steam** handles payment, library, and game files -- **EA App** handles identity and authentication — even for offline single-player +- **EA App** handles identity and authentication -First launch requires an internet connection and an EA account login. After that, EA App -caches credentials locally and subsequent launches work offline — but only until the token -expires or EA's servers go dark permanently. +First launch requires internet + EA account. After that, EA App caches credentials +locally and subsequent launches work offline — until the token expires or EA's servers +shut down permanently. -**What happens when EA shuts down authentication servers?** -The game becomes unplayable through legitimate means. EA has done this before (Battlefield 2, -The Sims Online, older Origin titles). For a 9-year-old game with a shrinking playerbase, -this is a real risk. +**If/when EA shuts down:** +- Community private server projects (like Kyber) may replace EA's infrastructure +- SWBF2 (2005, AppID 6060) is the zero-dependency alternative — no accounts, no + launchers, active community servers, runs perfectly through Proton -Community options if/when that happens: -- **Private servers** — the SWBF2 community has projects like Kyber for multiplayer. If EA - kills auth, expect the community to build replacement auth servers as they did for BF2 (BF2Hub, OpenSpy). -- **Play SWBF2 (2005) instead** — the classic 2005 Battlefront II runs natively on Linux - through Proton with zero launcher requirements, no accounts, no phoning home. - AppID: 6060. It just works. - -**Backing up credentials for machine transfers:** -EA App caches credentials inside the Wine prefix. Back up the entire compatdata directory: +**Migrating to another machine:** ```bash +# Back up the Wine prefix — EA credentials travel with it tar -czf swbf2-prefix-backup.tar.gz \ - /home/retro/.steam/steam/steamapps/compatdata/1237950/ + /home/retro/.steam/steam/steamapps/compatdata/1237950/ ``` -Restore it on another machine and the cached login travels with it — until the token expires -(EA tokens last weeks to months). Not a permanent solution but useful for migrations. +Tokens last weeks to months before requiring re-login. --- -## Why this is hard (technically) +## Why docker exec can't run Wine/Proton ---- - -## The bwrap problem (why you can't just docker exec) - -The WolfSteam container runs Steam as uid 1000 (`retro` inside container). `docker exec` carries high Linux capabilities (`CapEff ≈ 0xa8ac35fb`). -Steam processes have `CapEff=0`. - -When a high-cap shell tries to run bwrap (used by Steam's sniper/pressure-vessel runtime), -bwrap attempts a privileged uid-map path that fails: +Steam processes run with `CapEff=0`. When a high-cap process tries to run bwrap +(Steam's sniper/pressure-vessel sandbox), bwrap tries a privileged uid-map path: ``` setting up uid map: Permission denied ``` -This means you **cannot** run Proton or wine64 via `docker exec` — bwrap always fails. -Only Steam itself can properly launch programs through sniper+GE-Proton. +**Only Steam itself can launch programs through sniper+GE-Proton.** All Wine +operations must go through Steam's launch chain — hence the wrapper approach. --- -## Solution overview +## How it works -1. Intercept the Steam launch with a wrapper script (via launch options) -2. Spoof Origin registry entries so SWBF2 thinks its launcher is present -3. Skip link2ea:// entirely — launch `starwarsbattlefrontii.exe` directly +Steam passes a `link2ea://` URL as the "game executable" to GE-Proton. The wrapper +intercepts this, imports registry fixes, then passes the original URL through. +GE-Proton's `steam.exe` handles `link2ea://`, finds `Link2EA.exe` via the registry, +runs it, and EA Desktop authenticates the session before launching the game. -No EA account needed. No EA App login needed. +``` +Steam → wrapper → regedit (registry fixes) → exec original args + → GE-Proton steam.exe → link2ea:// → Link2EA.exe → EA Desktop → SWBF2 +``` --- ## Step-by-step -### 1. Find the WolfSteam container name and Steam user ID +### 1. Trigger Wine prefix creation + +SWBF2 must be launched at least once so Steam creates the Wine prefix and drops +`ea_app.msi` into it. Launch SWBF2 from Moonlight, wait ~10 seconds, then close it +(the "Origin is not installed" error is expected at this point). + +Verify the MSI appeared: +```bash +WOLF_CONTAINER=$(docker ps --format '{{.Names}}' | grep Wolf) +docker exec "$WOLF_CONTAINER" ls -lh \ + /home/retro/.steam/steam/steamapps/compatdata/1237950/pfx/drive_c/ea_app.msi +``` +Expected: ~227 MB file. + +### 2. Extract EA Desktop files on the host + +The MSI's `JunoConfigureRegistry` .NET custom action fails in Wine (it uses +`SetSecurityDescriptorSddlForm` for registry ACLs — unsupported in Wine). This +causes the entire install to roll back. Extract files on the host instead: ```bash WOLF_CONTAINER=$(docker ps --format '{{.Names}}' | grep Wolf) -echo "$WOLF_CONTAINER" -STEAM_UID=$(docker exec "$WOLF_CONTAINER" ls /home/retro/.steam/steam/userdata/) -echo "$STEAM_UID" +docker cp "$WOLF_CONTAINER:/home/retro/.steam/steam/steamapps/compatdata/1237950/pfx/drive_c/ea_app.msi" \ + /tmp/ea_app.msi -CONFIG_DIR="/home/retro/.steam/steam/userdata/$STEAM_UID/config" +sudo apt-get install -y msitools +mkdir -p /tmp/ea_app_extracted +msiextract -C /tmp/ea_app_extracted /tmp/ea_app.msi ``` -### 2. Lock localconfig.vdf against Steam overwriting it +### 3. Copy EA Desktop files into the Wine prefix -Steam uses atomic rename (write temp + rename) when saving config. -`chmod 444` on the file is bypassed by the rename. Lock the **directory** instead: +The MSI installs EA Desktop under a versioned directory with a symlink. +The version (e.g. `14.2.0.3345`) is whatever the extracted MSI contains: ```bash -docker exec "$WOLF_CONTAINER" chmod 555 "$CONFIG_DIR" -``` +EA_VERSION=$(ls /tmp/ea_app_extracted/Electronic\ Arts/EA\ Desktop/ | head -1) +# Usually "EA Desktop" — this is the versioned dir, renamed during real install +# Use the version from the failed-install symlink if present: +SYMLINK_TARGET=$(docker exec "$WOLF_CONTAINER" readlink \ + "/home/retro/.steam/steam/steamapps/compatdata/1237950/pfx/drive_c/Program Files/Electronic Arts/EA Desktop/EA Desktop" \ + 2>/dev/null || echo "14.2.0.3345") -### 3. Set SWBF2 launch options in localconfig.vdf +PFXBASE="/home/retro/.steam/steam/steamapps/compatdata/1237950/pfx/drive_c/Program Files/Electronic Arts/EA Desktop" -Kill Steam first so it flushes and releases the file, then edit: +docker exec "$WOLF_CONTAINER" bash -c " + rm -f '$PFXBASE/EA Desktop' + mkdir -p '$PFXBASE/$SYMLINK_TARGET' + ln -s '$SYMLINK_TARGET' '$PFXBASE/EA Desktop' +" -```bash -docker exec "$WOLF_CONTAINER" pkill -f steam.sh || true -sleep 3 - -CONFIG_FILE="$CONFIG_DIR/localconfig.vdf" - -# The file needs a LaunchOptions entry under AppID 1237950. -# Find the block and add/replace LaunchOptions: -docker exec "$WOLF_CONTAINER" grep -A5 '"1237950"' "$CONFIG_FILE" -# If LaunchOptions is missing, add it manually to the 1237950 block: -# "LaunchOptions" "STEAM_UNIX_SOCKET=/tmp/steam.sock /home/retro/ea_install.sh %command%" -``` - -The launch option value must be: -``` -STEAM_UNIX_SOCKET=/tmp/steam.sock /home/retro/ea_install.sh %command% -``` - -### 4. Write the Origin registry spoof - -SWBF2's binary checks for Origin in the registry before starting. Spoof it by writing -directly to Wine's system.reg (plain text file — no Wine needed): - -```bash -SYSREG="/home/retro/.steam/steam/steamapps/compatdata/1237950/pfx/system.reg" -TIMESTAMP=$(date +%s) - -docker exec "$WOLF_CONTAINER" bash -c "cat >> '$SYSREG' << 'REGEOF' - -[Software\\\\Origin] $TIMESTAMP -\"ClientPath\"=\"C:\\\\\\\\Program Files\\\\\\\\Electronic Arts\\\\\\\\EA Desktop\\\\\\\\EA Desktop\\\\\\\\EADesktop.exe\" -\"InstallDir\"=\"C:\\\\\\\\Program Files\\\\\\\\Electronic Arts\\\\\\\\EA Desktop\\\\\\\\EA Desktop\\\\\\\\\" - -[Software\\\\Wow6432Node\\\\Origin] $TIMESTAMP -\"ClientPath\"=\"C:\\\\\\\\Program Files\\\\\\\\Electronic Arts\\\\\\\\EA Desktop\\\\\\\\EA Desktop\\\\\\\\EADesktop.exe\" -\"InstallDir\"=\"C:\\\\\\\\Program Files\\\\\\\\Electronic Arts\\\\\\\\EA Desktop\\\\\\\\EA Desktop\\\\\\\\\" -REGEOF" +docker cp "/tmp/ea_app_extracted/Electronic Arts/EA Desktop/EA Desktop/." \ + "$WOLF_CONTAINER:$PFXBASE/$SYMLINK_TARGET/" # Verify -docker exec "$WOLF_CONTAINER" grep -A3 'Software\\\\Origin' "$SYSREG" +docker exec "$WOLF_CONTAINER" find "$PFXBASE" -name "Link2EA.exe" ``` -### 5. Write the launch wrapper +### 4. Write registry fix files to drive_c -The wrapper receives Steam's full launch chain as `$@` (args 1–11 are the -sniper+GE-Proton preamble, arg 12 is normally `link2ea://...`). Replace the last -arg with the actual game executable: +These are imported into the Wine registry on each launch via the wrapper. +Writing to drive_c ensures they survive wineserver restarts (unlike direct +system.reg edits which get overwritten). + +```bash +PFXC="$WOLF_CONTAINER:/home/retro/.steam/steam/steamapps/compatdata/1237950/pfx/drive_c" + +# link2ea:// protocol handler — tells Wine how to run Link2EA.exe +cat > /tmp/link2ea_fix.reg << 'EOF' +Windows Registry Editor Version 5.00 + +[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\link2ea] +@="URL:link2ea Protocol" +"URL Protocol"="" + +[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\link2ea\shell\open\command] +@="\"C:\\Program Files\\Electronic Arts\\EA Desktop\\EA Desktop\\Link2EA.exe\" \"%1\"" +EOF + +# EA Desktop Windows services — EALocalHostSvc provides local IPC that +# Link2EA.exe needs; without it launch fails with RPC_S_SERVER_UNAVAILABLE +cat > /tmp/ea_services.reg << 'EOF' +Windows Registry Editor Version 5.00 + +[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EALocalHostSvc] +"Type"=dword:00000010 +"Start"=dword:00000002 +"ErrorControl"=dword:00000001 +"ImagePath"="C:\\Program Files\\Electronic Arts\\EA Desktop\\EA Desktop\\EALocalHostSvc.exe" +"DisplayName"="EA Local Host Service" +"ObjectName"="LocalSystem" + +[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EABackgroundService] +"Type"=dword:00000010 +"Start"=dword:00000002 +"ErrorControl"=dword:00000001 +"ImagePath"="C:\\Program Files\\Electronic Arts\\EA Desktop\\EA Desktop\\EABackgroundService.exe" +"DisplayName"="EA Background Service" +"ObjectName"="LocalSystem" +EOF + +docker cp /tmp/link2ea_fix.reg "$PFXC/link2ea_fix.reg" +docker cp /tmp/ea_services.reg "$PFXC/ea_services.reg" +``` + +### 5. Lock localconfig.vdf and set launch options + +Steam overwrites localconfig.vdf on shutdown via atomic rename (temp file + +rename). `chmod 444` on the file is bypassed. Lock the **directory** instead: + +```bash +STEAM_UID=$(docker exec "$WOLF_CONTAINER" ls /home/retro/.steam/steam/userdata/) +CONFIG_DIR="/home/retro/.steam/steam/userdata/$STEAM_UID/config" +CONFIG_FILE="$CONFIG_DIR/localconfig.vdf" + +# Stop Steam so it flushes before we edit +docker exec "$WOLF_CONTAINER" pkill -f steam.sh || true +sleep 5 + +# Lock directory +docker exec "$WOLF_CONTAINER" chmod 555 "$CONFIG_DIR" + +# Add launch options for AppID 1237950 +# Find the 1237950 block and insert/replace LaunchOptions +docker exec "$WOLF_CONTAINER" python3 - "$CONFIG_FILE" << 'PYEOF' +import sys, re +path = sys.argv[1] +with open(path, 'r') as f: + content = f.read() + +launch_opt = 'STEAM_UNIX_SOCKET=/tmp/steam.sock /home/retro/ea_install.sh %command%' + +# Replace existing LaunchOptions in 1237950 block if present +new = re.sub( + r'("1237950".*?"LaunchOptions"\s*)"[^"]*"', + rf'\1"{launch_opt}"', + content, flags=re.DOTALL +) + +if new == content: + # LaunchOptions key missing — add it after the "1237950" line + new = re.sub( + r'("1237950"\s*\n\s*\{)', + rf'\1\n\t\t\t\t"LaunchOptions"\t\t"{launch_opt}"', + content + ) + +with open(path, 'w') as f: + f.write(new) +print("Done") +PYEOF + +# Verify +docker exec "$WOLF_CONTAINER" grep -A3 '"1237950"' "$CONFIG_FILE" | grep -i launch +``` + +### 6. Write the wrapper script ```bash cat > /tmp/ea_install.sh << 'EOF' #!/bin/bash echo "=== launch $(date) ===" >> /tmp/ea_install.log -GAME_EXE="/home/retro/.steam/steam/steamapps/common/STAR WARS Battlefront II/starwarsbattlefrontii.exe" -exec "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9" "${10}" "${11}" "$GAME_EXE" +# Import registry fixes on every launch (survives wineserver restarts) +"$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9" "${10}" "${11}" regedit /S "C:\\link2ea_fix.reg" +"$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9" "${10}" "${11}" regedit /S "C:\\ea_services.reg" +# Pass original args through — Steam's link2ea:// URL goes to GE-Proton → Link2EA.exe +exec "$@" EOF chmod +x /tmp/ea_install.sh docker cp /tmp/ea_install.sh "$WOLF_CONTAINER":/home/retro/ea_install.sh ``` -### 6. Launch SWBF2 in Moonlight — first-time EA login +### 7. First launch -On first launch Steam passes `link2ea://launchgame/1237950?platform=steam&theme=swbfii` -to GE-Proton, which hands it to `Link2EA.exe`. EA App opens and shows a login screen. - -**Vulkan shader compilation** appears before the game loads on first run. Let it complete -— do not skip it. It only runs once and takes several minutes. - -**EA App login:** -1. Log in with your EA account credentials -2. Check "Stay logged in" / "Remember me" — this caches the token locally -3. EA App links your Steam purchase to your EA account -4. The game launches - -**After first login**, credentials are cached in the Wine prefix at: -``` -compatdata/1237950/pfx/drive_c/users/steamuser/AppData/Local/EADesktop/ -``` -Subsequent launches skip the login screen entirely. - -### 7. Restore clean state (after confirmed working) - -```bash -# Restore directory to writable so Steam can save normally -docker exec "$WOLF_CONTAINER" chmod 755 "$CONFIG_DIR" - -# Remove LaunchOptions for 1237950 from localconfig.vdf while Steam is stopped -``` +1. Reconnect to Moonlight and launch SWBF2 +2. **Let Vulkan shaders compile** — do not skip, takes several minutes, only happens once +3. EA App authenticates via your linked Steam/EA account (no manual login if accounts are linked) +4. Game loads --- -## Background: what Steam actually passes to the wrapper +## Is this fragile? Will it work on a fresh install? -``` -$1 = /path/to/steam-launch-wrapper -$2 = -- -$3 = /path/to/reaper -$4 = SteamLaunch -$5 = AppId=1237950 -$6 = -- -$7 = /path/to/SteamLinuxRuntime_sniper/_v2-entry-point -$8 = --verb=waitforexitandrun -$9 = -- -$10 = /path/to/GE-Proton10-34/proton -$11 = waitforexitandrun -$12 = link2ea://launchgame/1237950?platform=steam&theme=swbfii ← we replace this -``` +**Honest assessment:** ---- +| Component | Fresh install safe? | Notes | +|-----------|-------------------|-------| +| EA Desktop files in Wine prefix | ✅ | Extracted from MSI in game files | +| Registry fixes (.reg files) | ✅ | Imported on every launch via wrapper | +| Launch options in localconfig.vdf | ✅ | Set by script | +| Config dir lock (chmod 555) | ✅ | Set by script | +| ea_app.msi in drive_c | ⚠️ | Requires one failed launch first to appear | +| EA account link | ⚠️ | One-time manual step | +| Vulkan shader cache | ⚠️ | Recompiles on fresh prefix — takes minutes | +| EA token in Wine prefix | ⚠️ | Requires login if prefix deleted or token expired | -## What doesn't work (and why) +**The catch:** The Wine prefix (`compatdata/1237950/`) is recreated from scratch if deleted. +All file copies and registry entries live inside it. A fresh install needs all steps run again +— but the automation handles that. -### Running msiexec / Wine via docker exec -`docker exec` carries Linux capabilities that break bwrap. Any attempt to run -Proton/wine64 outside Steam's own launch chain gets: -``` -setting up uid map: Permission denied -``` - -### Running the EA App MSI through Wine (INST-14-1603) -The MSI's `JunoConfigureRegistry` .NET custom action uses `SetSecurityDescriptorSddlForm` -to set registry ACLs. Wine doesn't support this — the action returns 0 (failure), -causing the entire install to roll back. `DISABLEROLLBACK=1` doesn't help because -MSI logs the product as already-registered from the first attempt, causing subsequent -runs to produce an empty log and exit. - -### link2ea:// approach with EA account -EA App requires an EA account linked to your Steam account. `ea.com/signup` is -unreliable. Even with an account, EA Desktop must be installed in the Wine prefix -(see msiextract bypass below if needed). Bypassing the game exe directly is simpler. - -### msiextract bypass (if EA App files are needed for something else) -If you need EA Desktop files in the prefix for another reason: -```bash -# Copy MSI out of container (appears in drive_c after first launch attempt) -docker cp "$WOLF_CONTAINER:/home/retro/.steam/steam/steamapps/compatdata/1237950/pfx/drive_c/ea_app.msi" \ - /tmp/ea_app.msi - -# Extract on host (bypasses JunoConfigureRegistry entirely) -sudo apt-get install -y msitools -mkdir -p /tmp/ea_app_extracted -msiextract -C /tmp/ea_app_extracted /tmp/ea_app.msi - -PFXBASE="/home/retro/.steam/steam/steamapps/compatdata/1237950/pfx/drive_c/Program Files/Electronic Arts/EA Desktop" -docker exec "$WOLF_CONTAINER" bash -c " - [ -L '$PFXBASE/EA Desktop' ] && rm '$PFXBASE/EA Desktop' - mkdir -p '$PFXBASE/14.2.0.3345' - ln -s 14.2.0.3345 '$PFXBASE/EA Desktop' -" -docker cp "/tmp/ea_app_extracted/Electronic Arts/EA Desktop/EA Desktop/." \ - "$WOLF_CONTAINER:$PFXBASE/14.2.0.3345/" -``` +**The one irreducible manual step:** Linking your EA account to Steam (done once at ea.com, +persists across reinstalls via EA's servers). --- ## Troubleshooting -### Game exits in ~6 seconds, no popup -Check wrapper log inside container: +### "Origin is not installed" popup +The game binary checks for Origin before calling link2ea://. This happens when: +- The wrapper didn't run (check launch options are set) +- The wrapper ran but regedit failed (check `tail /tmp/ea_install.log`) + +### `link2ea://` fails with ret 31 (SE_ERR_NOASSOC) +`link2ea_fix.reg` wasn't imported. Check drive_c has the file and wrapper ran both regedits. + +### RPC_S_SERVER_UNAVAILABLE (0x800706ba) in wine log +`ea_services.reg` wasn't imported or EALocalHostSvc failed to register. Check wrapper log. + +### Game exits immediately, no popup, no log +Wrapper isn't being called. Config dir may not be chmod 555 or launch options missing. +```bash +docker exec "$WOLF_CONTAINER" stat "$CONFIG_DIR" | grep Access +docker exec "$WOLF_CONTAINER" grep -A5 '"1237950"' "$CONFIG_FILE" | grep -i launch +``` + +### Collecting logs after a failure ```bash docker exec "$WOLF_CONTAINER" bash -c " - cat /tmp/ea_install.log | tail -20 - find /home/retro/.steam/steam/steamapps/compatdata/1237950/ -name '*.log' \ - -newer /tmp/ea_install.log 2>/dev/null | xargs tail -20 2>/dev/null + tail -20 /tmp/ea_install.log + echo '---' + grep -E '(err:|link2ea|origin|RPC)' /home/retro/steam-1237950.log | tail -20 " ``` -### "Origin is not installed" popup -Origin registry entries missing. Repeat step 4 and verify: -```bash -docker exec "$WOLF_CONTAINER" grep -A3 'Software\\\\Origin' \ - '/home/retro/.steam/steam/steamapps/compatdata/1237950/pfx/system.reg' -``` - -### Wrapper never runs (Steam ignores launch options) -Steam wrote config before chmod 555 was applied. Kill Steam, verify chmod 555 is set -on the config directory, edit localconfig.vdf, then start Steam again. - -### localconfig.vdf gets overwritten on Steam shutdown -`chmod 555` on the directory (not the file) prevents the atomic rename Steam uses. - -### wine64 segfaults outside Steam (exit 139) -GE-Proton10's wine64 requires the sniper runtime. Never call it via `docker exec`. - --- ## Key paths (inside WolfSteam container) @@ -289,9 +314,11 @@ GE-Proton10's wine64 requires the sniper runtime. Never call it via `docker exec | Path | Description | |------|-------------| | `/home/retro/.steam/steam/steamapps/compatdata/1237950/pfx/` | SWBF2 Wine prefix | -| `/home/retro/.steam/steam/steamapps/compatdata/1237950/pfx/system.reg` | Wine HKLM registry (plain text) | -| `/home/retro/.steam/steam/steamapps/compatdata/1237950/pfx/drive_c/ea_app.msi` | EA App MSI (~227 MB, appears after first launch) | -| `/home/retro/.steam/steam/steamapps/common/STAR WARS Battlefront II/starwarsbattlefrontii.exe` | Actual game binary | -| `/home/retro/.steam/steam/userdata//config/localconfig.vdf` | Steam per-user config (launch options) | -| `/home/retro/ea_install.sh` | Launch wrapper script | -| `/tmp/ea_install.log` | Wrapper log (inside container, resets on container restart) | +| `/home/retro/.steam/steam/steamapps/compatdata/1237950/pfx/system.reg` | Wine HKLM registry | +| `/home/retro/.steam/steam/steamapps/compatdata/1237950/pfx/drive_c/ea_app.msi` | EA App MSI (~227 MB) | +| `/home/retro/.steam/steam/steamapps/compatdata/1237950/pfx/drive_c/link2ea_fix.reg` | link2ea protocol handler reg | +| `/home/retro/.steam/steam/steamapps/compatdata/1237950/pfx/drive_c/ea_services.reg` | EA service registrations | +| `/home/retro/.steam/steam/steamapps/common/STAR WARS Battlefront II/` | Game files | +| `/home/retro/.steam/steam/userdata//config/localconfig.vdf` | Steam launch options | +| `/home/retro/ea_install.sh` | Launch wrapper | +| `/tmp/ea_install.log` | Wrapper log (resets on container restart) | From 80842767385d96290d101a7155e6da325435fabe Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 22 Jun 2026 12:38:05 +0000 Subject: [PATCH 4/4] feat(wolf): add setup-swbf2 command for full SWBF2 2017 Wolf/Moonlight setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Automates the complete working solution for SWBF2 (AppID 1237950) on Wolf: 1. Extracts EA Desktop from ea_app.msi using msiextract on the host, bypassing JunoConfigureRegistry Wine incompatibility that causes MSI rollback 2. Copies EA Desktop files (Link2EA.exe, EALocalHostSvc.exe, etc.) into the Wine prefix at the versioned path with symlink 3. Writes link2ea_fix.reg and ea_services.reg into drive_c so they persist across Wine prefix operations 4. Installs a launch wrapper (/home/retro/ea_install.sh) that runs regedit via Steam's sniper+GE-Proton launch chain — required because direct edits to system.reg are overwritten when wineserver flushes on shutdown 5. Sets LaunchOptions for AppID 1237950 in localconfig.vdf and locks the config directory (chmod 555) to prevent Steam overwriting it via atomic rename on shutdown Run after: Steam open in Moonlight, GE-Proton set, SWBF2 launched once (triggers Wine prefix + ea_app.msi creation), EA account linked at ea.com. Co-Authored-By: Claude Sonnet 4.6 Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs --- services/wolf.sh | 262 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 261 insertions(+), 1 deletion(-) diff --git a/services/wolf.sh b/services/wolf.sh index 3218b0f..1e50282 100644 --- a/services/wolf.sh +++ b/services/wolf.sh @@ -2065,6 +2065,265 @@ PYEOF echo "Expected path: $_dx_log" fi ;; + setup-swbf2) + # Full automated setup for Star Wars Battlefront II (2017, AppID 1237950) + # on Wolf/Moonlight with GE-Proton. Implements the msiextract bypass for + # the JunoConfigureRegistry Wine incompatibility, installs EA Desktop files + # into the Wine prefix, and wires up a launch wrapper so registry fixes + # survive wineserver restarts. + # + # Prerequisites (do these first, then run this command): + # 1. Wolf is running and Steam is open in Moonlight + # 2. GE-Proton10-34+ is installed (./manage.sh ge-proton) + # 3. SWBF2 (AppID 1237950) is set to use GE-Proton in Steam → Compatibility + # 4. msitools is installed on the host (sudo apt-get install -y msitools) + # 5. Your EA account is linked to your Steam account at ea.com (one-time manual step) + # 6. Launch SWBF2 once from Moonlight, wait ~10s for the "Origin is not installed" + # error, then close it — this triggers Wine prefix creation and drops ea_app.msi + # + # After this command completes: launch SWBF2 from Moonlight. Let Vulkan + # shaders compile on first run (takes several minutes, only once). EA App + # authenticates via your linked Steam/EA account and the game launches. + # + # Usage: ./manage.sh setup-swbf2 + _sw_appid="1237950" + _sw_sh=$(_steam_home) + if [ -z "$_sw_sh" ]; then + echo "Steam home not found. Start Wolf (./manage.sh start) and open Steam in Moonlight first." + exit 1 + fi + _sw_container=$(docker ps --format '{{.Names}}' | grep -i WolfSteam | head -1) + if [ -z "$_sw_container" ]; then + echo "WolfSteam container is not running. Start Wolf: ./manage.sh start" + exit 1 + fi + _sw_pfxc="$_sw_sh/.steam/steam/steamapps/compatdata/$_sw_appid/pfx/drive_c" + _sw_msi="$_sw_pfxc/ea_app.msi" + + echo "=== SWBF2 (2017) Wolf/Moonlight Setup ===" + echo "" + + # ── Step 1: verify Wine prefix exists ────────────────────────────────── + if [ ! -d "$_sw_pfxc" ]; then + echo "ERROR: Wine prefix not found at $_sw_pfxc" + echo "" + echo "Required setup before running this command:" + echo " 1. In Steam (via Moonlight): right-click SWBF2 → Properties → Compatibility" + echo " → Force GE-Proton10-34 (or later)" + echo " 2. Click Play on SWBF2 — wait ~10 seconds for 'Origin is not installed' error" + echo " 3. Close the error and return here" + exit 1 + fi + echo "[1/6] Wine prefix found: OK" + + # ── Step 2: check ea_app.msi exists ──────────────────────────────────── + if [ ! -f "$_sw_msi" ]; then + echo "" + echo "ERROR: ea_app.msi not found at $_sw_msi" + echo "" + echo "SWBF2 must be launched once so Steam drops ea_app.msi into the Wine prefix." + echo " 1. Open Steam in Moonlight" + echo " 2. Click Play on SWBF2" + echo " 3. Wait ~10 seconds — you will see an 'Origin is not installed' error" + echo " 4. Close the error popup" + echo " 5. Re-run: ./manage.sh setup-swbf2" + echo "" + echo "Expected file size: ~227 MB" + exit 1 + fi + _sw_msi_size=$(stat -c%s "$_sw_msi" 2>/dev/null || echo 0) + if [ "$_sw_msi_size" -lt 50000000 ]; then + echo "WARNING: ea_app.msi looks too small ($_sw_msi_size bytes, expected ~227 MB)." + echo "It may still be copying. Try again in a moment." + exit 1 + fi + echo "[2/6] ea_app.msi found ($(( _sw_msi_size / 1048576 )) MB): OK" + + # ── Step 3: extract MSI on the host (bypasses JunoConfigureRegistry) ── + echo "[3/6] Extracting EA Desktop files from MSI (this takes ~30s)..." + if ! command -v msiextract >/dev/null 2>&1; then + echo "ERROR: msitools not installed. Run: sudo apt-get install -y msitools" + exit 1 + fi + _sw_extract_dir="/tmp/ea_app_extracted_$$" + rm -rf "$_sw_extract_dir" + mkdir -p "$_sw_extract_dir" + if ! msiextract -C "$_sw_extract_dir" "$_sw_msi" >/dev/null 2>&1; then + echo "ERROR: msiextract failed. Check that msitools is properly installed." + rm -rf "$_sw_extract_dir" + exit 1 + fi + _sw_ea_src=$(find "$_sw_extract_dir" -maxdepth 4 \ + -path "*/Electronic Arts/EA Desktop/EA Desktop" -type d 2>/dev/null | head -1) + if [ -z "$_sw_ea_src" ] || [ ! -f "$_sw_ea_src/Link2EA.exe" ]; then + echo "ERROR: Link2EA.exe not found after extraction. MSI structure may have changed." + echo "Expected: /Electronic Arts/EA Desktop/EA Desktop/Link2EA.exe" + ls -la "$_sw_extract_dir/Electronic Arts/EA Desktop/" 2>/dev/null || true + rm -rf "$_sw_extract_dir" + exit 1 + fi + echo " Extracted to: $_sw_ea_src" + echo " $(ls "$_sw_ea_src" | wc -l) files found including Link2EA.exe" + + # ── Step 4: copy EA Desktop files into Wine prefix ───────────────────── + echo "[4/6] Installing EA Desktop files into Wine prefix..." + _sw_ea_dest_base="$_sw_pfxc/Program Files/Electronic Arts/EA Desktop" + # Determine the version directory name from the extracted content. + # The MSI extracts to "EA Desktop" but the real install uses a versioned dir + # with a symlink. Use the same version string if a broken symlink exists from + # a failed install attempt; otherwise default to 14.2.0.3345. + _sw_ea_version=$( \ + docker exec "$_sw_container" \ + readlink "/home/retro/.steam/steam/steamapps/compatdata/$_sw_appid/pfx/drive_c/Program Files/Electronic Arts/EA Desktop/EA Desktop" \ + 2>/dev/null || echo "14.2.0.3345") + _sw_ea_dest="$_sw_ea_dest_base/$_sw_ea_version" + sudo mkdir -p "$_sw_ea_dest" + sudo cp -r "$_sw_ea_src/." "$_sw_ea_dest/" + sudo chown -R 1000:1000 "$_sw_ea_dest_base" + # Remove any broken symlink, then create a clean one + sudo rm -f "$_sw_ea_dest_base/EA Desktop" + docker exec "$_sw_container" bash -c \ + "ln -sf '$_sw_ea_version' '/home/retro/.steam/steam/steamapps/compatdata/$_sw_appid/pfx/drive_c/Program Files/Electronic Arts/EA Desktop/EA Desktop'" \ + 2>/dev/null || sudo ln -sf "$_sw_ea_version" "$_sw_ea_dest_base/EA Desktop" + if [ ! -f "$_sw_ea_dest/Link2EA.exe" ]; then + echo "ERROR: Copy failed — Link2EA.exe not found at $_sw_ea_dest/Link2EA.exe" + rm -rf "$_sw_extract_dir" + exit 1 + fi + echo " EA Desktop installed to: $( echo "$_sw_ea_dest" | sed "s|$_sw_sh||" )" + rm -rf "$_sw_extract_dir" + + # ── Step 5: write .reg files and wrapper script into Wine prefix ──────── + echo "[5/6] Writing registry fix files and launch wrapper..." + _sw_drive_c="$_sw_pfxc" + + # link2ea:// protocol handler — points Wine at Link2EA.exe + sudo tee "$_sw_drive_c/link2ea_fix.reg" > /dev/null << 'REGEOF' +Windows Registry Editor Version 5.00 + +[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\link2ea] +@="URL:link2ea Protocol" +"URL Protocol"="" + +[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\link2ea\shell\open\command] +@="\"C:\\Program Files\\Electronic Arts\\EA Desktop\\EA Desktop\\Link2EA.exe\" \"%1\"" +REGEOF + + # EA Desktop Windows services — EALocalHostSvc provides local IPC that + # Link2EA.exe requires; without it launch fails with RPC_S_SERVER_UNAVAILABLE + sudo tee "$_sw_drive_c/ea_services.reg" > /dev/null << 'REGEOF' +Windows Registry Editor Version 5.00 + +[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EALocalHostSvc] +"Type"=dword:00000010 +"Start"=dword:00000002 +"ErrorControl"=dword:00000001 +"ImagePath"="C:\\Program Files\\Electronic Arts\\EA Desktop\\EA Desktop\\EALocalHostSvc.exe" +"DisplayName"="EA Local Host Service" +"ObjectName"="LocalSystem" + +[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EABackgroundService] +"Type"=dword:00000010 +"Start"=dword:00000002 +"ErrorControl"=dword:00000001 +"ImagePath"="C:\\Program Files\\Electronic Arts\\EA Desktop\\EA Desktop\\EABackgroundService.exe" +"DisplayName"="EA Background Service" +"ObjectName"="LocalSystem" +REGEOF + sudo chown 1000:1000 "$_sw_drive_c/link2ea_fix.reg" "$_sw_drive_c/ea_services.reg" + + # Launch wrapper — runs regedit via Steam's launch chain on every launch + # so registry entries survive wineserver restarts. Direct edits to + # system.reg are overwritten by wineserver when it flushes to disk. + sudo tee /tmp/ea_install_wrapper.sh > /dev/null << 'WRAPEOF' +#!/bin/bash +echo "=== launch $(date) ===" >> /tmp/ea_install.log +"$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9" "${10}" "${11}" regedit /S "C:\\link2ea_fix.reg" +"$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9" "${10}" "${11}" regedit /S "C:\\ea_services.reg" +exec "$@" +WRAPEOF + chmod +x /tmp/ea_install_wrapper.sh + docker cp /tmp/ea_install_wrapper.sh "$_sw_container":/home/retro/ea_install.sh + docker exec "$_sw_container" chmod +x /home/retro/ea_install.sh + rm -f /tmp/ea_install_wrapper.sh + echo " .reg files and wrapper script installed." + + # ── Step 6: set LaunchOptions in localconfig.vdf and lock config dir ─── + echo "[6/6] Setting Steam launch options and locking localconfig.vdf..." + _sw_steam_uid=$(sudo ls "$_sw_sh/.steam/steam/userdata/" 2>/dev/null | head -1) + if [ -z "$_sw_steam_uid" ]; then + echo "WARNING: No Steam userdata found. You may need to have logged into Steam first." + echo " Open Steam in Moonlight, sign in, then re-run this command." + else + _sw_cfg_dir="$_sw_sh/.steam/steam/userdata/$_sw_steam_uid/config" + _sw_cfg_file="$_sw_cfg_dir/localconfig.vdf" + if [ ! -f "$_sw_cfg_file" ]; then + echo "WARNING: localconfig.vdf not found at $_sw_cfg_file" + echo " Open Steam in Moonlight first, then re-run." + else + # Stop Steam so it flushes current state before we edit + docker exec "$_sw_container" pkill -f steam.sh 2>/dev/null || true + sleep 5 + + # Make sure config dir is writable long enough to edit the file + sudo chmod 755 "$_sw_cfg_dir" 2>/dev/null || true + + _sw_launch_opt='STEAM_UNIX_SOCKET=/tmp/steam.sock /home/retro/ea_install.sh %command%' + sudo python3 - "$_sw_cfg_file" "$_sw_launch_opt" << 'PYEOF' +import sys, re +path, launch_opt = sys.argv[1], sys.argv[2] +with open(path, 'r') as f: + content = f.read() +new = re.sub( + r'("1237950".*?"LaunchOptions"\s*)"[^"]*"', + rf'\1"{launch_opt}"', + content, flags=re.DOTALL +) +if new == content: + new = re.sub( + r'("1237950"\s*\n\s*\{)', + rf'\1\n\t\t\t\t"LaunchOptions"\t\t"{launch_opt}"', + content + ) +if new == content: + print("WARNING: 1237950 block not found in localconfig.vdf — launch options not set.") + print("In Steam: right-click SWBF2 → Properties → Launch Options, enter:") + print(" STEAM_UNIX_SOCKET=/tmp/steam.sock /home/retro/ea_install.sh %command%") +else: + with open(path, 'w') as f: + f.write(new) + print(" LaunchOptions set for AppID 1237950.") +PYEOF + sudo chown 1000:1000 "$_sw_cfg_file" + + # Lock the config directory so Steam can't overwrite localconfig.vdf + # via atomic rename (temp file + rename). chmod 444 on the file is + # bypassed; locking the directory blocks the rename-into. + sudo chmod 555 "$_sw_cfg_dir" + echo " Config directory locked (chmod 555) to preserve launch options." + fi + fi + + echo "" + echo "=== Setup complete ===" + echo "" + echo "Next steps:" + echo " 1. In Steam (Moonlight): right-click SWBF2 → Properties → Compatibility" + echo " → Force a specific Steam Play compatibility tool → GE-Proton10-34 (or later)" + echo " 2. Click Play on SWBF2" + echo " 3. Let Vulkan shaders compile — do NOT skip, takes several minutes, only happens once" + echo " 4. EA App will authenticate via your linked Steam/EA account (no manual login needed" + echo " if accounts are linked at ea.com)" + echo " 5. Game should launch" + echo "" + echo "Troubleshooting:" + echo " ./manage.sh diagnose-ea $_sw_appid - check registry state" + echo " docker exec \$container tail /tmp/ea_install.log - check wrapper log" + echo "" + echo "Note: If the config dir was not writable (Steam not stopped cleanly), set launch" + echo "options manually in Steam → SWBF2 → Properties → Launch Options:" + echo " STEAM_UNIX_SOCKET=/tmp/steam.sock /home/retro/ea_install.sh %command%" + ;; fix-perms) # Wolf creates each app's home dir under WOLF_STATE_DIR// # and mounts it as /home/retro inside the app container. If anything in @@ -2099,7 +2358,7 @@ PYEOF _manage_wolf_complete() { local cur="${COMP_WORDS[COMP_CWORD]}" local commands="start stop restart logs status pin update apps reorder - add-web ge-proton games fix-ea-game wait-ea-app + add-web ge-proton games setup-swbf2 fix-ea-game wait-ea-app install-ea-app diagnose-ea fix-perms install-completion backup" COMPREPLY=( $(compgen -W "$commands" -- "$cur") ) } @@ -2156,6 +2415,7 @@ COMPEOF echo " ./manage.sh add-web [name] [url] - Add a URL shortcut tile (Firefox kiosk)" echo " ./manage.sh ge-proton [version] - Install GE-Proton (latest, or pin a version)" echo " ./manage.sh games - List games; pick one to apply the EA fix" + echo " ./manage.sh setup-swbf2 - Full SWBF2 2017 setup (EA Desktop + wrapper, see docs/SWBF2-2017-wolf-setup.md)" echo " ./manage.sh fix-ea-game [appid] - Apply EA fix directly (default: SWBF2 1237950)" echo " ./manage.sh wait-ea-app [appid] - Watch for EA App to install, then register link2ea:// handler" echo " ./manage.sh install-ea-app [appid] - Run EA App installer inside container (GUI appears in Moonlight)"