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 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
This commit is contained in:
Claude
2026-06-22 04:25:26 +00:00
parent 0202515163
commit 6b385e62ba
+148 -147
View File
@@ -9,11 +9,13 @@
## Why this is hard ## Why this is hard
SWBF2 (2017) is an EA game. EA mandated their **EA App** launcher for all EA Steam titles. 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")`. On launch, Steam passes `link2ea://launchgame/1237950?platform=steam&theme=swbfii` as the
GE-Proton's `steam.exe` intercepts that URL, finds `Link2EA.exe` from the EA Desktop install, and "executable" to GE-Proton. The game binary itself also checks for Origin/EA App in the
hands off to the EA App which then launches the actual game. 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, 1. Intercept the Steam launch with a wrapper script (via launch options)
then pass control back to Steam's real launch chain. 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 `$@`: No EA account needed. No EA App login needed.
```
steam-launch-wrapper -- reaper SteamLaunch AppId=1237950 -- <sniper> --verb=waitforexitandrun -- <proton> waitforexitandrun <game>
```
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.
--- ---
## Step-by-step ## Step-by-step
### 1. Lock localconfig.vdf against Steam overwriting it ### 1. Find the WolfSteam container name and Steam user ID
Steam uses atomic rename (write temp + rename) when saving config.
`chmod 444` on the file is bypassed. Lock the **directory** instead:
```bash ```bash
WOLF_CONTAINER="WolfSteam_XXXXXXXXXXXXXXXX" # docker ps to find exact name WOLF_CONTAINER=$(docker ps --format '{{.Names}}' | grep Wolf)
CONFIG_DIR="/home/retro/.steam/steam/userdata/XXXXXXXXX/config" echo "$WOLF_CONTAINER"
# Find container name STEAM_UID=$(docker exec "$WOLF_CONTAINER" ls /home/retro/.steam/steam/userdata/)
docker ps --format '{{.Names}}' | grep Wolf echo "$STEAM_UID"
# Find Steam user ID CONFIG_DIR="/home/retro/.steam/steam/userdata/$STEAM_UID/config"
docker exec "$WOLF_CONTAINER" ls /home/retro/.steam/steam/userdata/ ```
### 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" 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 ```bash
CONFIG_FILE="$CONFIG_DIR/localconfig.vdf"
# Kill Steam so it flushes and stops watching
docker exec "$WOLF_CONTAINER" pkill -f steam.sh || true docker exec "$WOLF_CONTAINER" pkill -f steam.sh || true
sleep 3 sleep 3
# Edit — find the LaunchOptions line for AppID 1237950 CONFIG_FILE="$CONFIG_DIR/localconfig.vdf"
# Add before it if missing:
docker exec "$WOLF_CONTAINER" bash -c " # The file needs a LaunchOptions entry under AppID 1237950.
sed -i '/\"1237950\"/,/}/ s/\"LaunchOptions\"\s*\"[^\"]*\"/\"LaunchOptions\"\t\t\"STEAM_UNIX_SOCKET=\/tmp\/steam.sock \/home\/retro\/ea_install.sh %command%\"/' '$CONFIG_FILE' # Find the block and add/replace LaunchOptions:
" docker exec "$WOLF_CONTAINER" grep -A5 '"1237950"' "$CONFIG_FILE"
# Or if LaunchOptions key doesn't exist yet, add it manually. # If LaunchOptions is missing, add it manually to the 1237950 block:
# Verify: # "LaunchOptions" "STEAM_UNIX_SOCKET=/tmp/steam.sock /home/retro/ea_install.sh %command%"
docker exec "$WOLF_CONTAINER" grep -A5 '"1237950"' "$CONFIG_FILE" | grep LaunchOptions
``` ```
### 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 ### 4. Write the Origin registry spoof
EA Desktop files, then execs the real game:
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 111 are the
sniper+GE-Proton preamble, arg 12 is normally `link2ea://...`). Replace the last
arg with the actual game executable:
```bash ```bash
cat > /tmp/ea_install.sh << 'EOF' cat > /tmp/ea_install.sh << 'EOF'
#!/bin/bash #!/bin/bash
echo "=== ea_install.sh called $(date) ===" >> /tmp/ea_install.log echo "=== launch $(date) ===" >> /tmp/ea_install.log
echo "Args: $@" >> /tmp/ea_install.log GAME_EXE="/home/retro/.steam/steam/steamapps/common/STAR WARS Battlefront II/starwarsbattlefrontii.exe"
"$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9" "${10}" "${11}" \ exec "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9" "${10}" "${11}" "$GAME_EXE"
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 "$@"
EOF EOF
chmod +x /tmp/ea_install.sh chmod +x /tmp/ea_install.sh
docker cp /tmp/ea_install.sh "$WOLF_CONTAINER":/home/retro/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 ```bash
MSI_SRC="/home/retro/.steam/steam/steamapps/common/STAR WARS Battlefront II/__Installer/Origin/redist/internal/EAappInstaller.exe" # Restore directory to writable so Steam can save normally
# EAappInstaller.exe is a WiX Burn bootstrapper — the real MSI is buried inside. docker exec "$WOLF_CONTAINER" chmod 755 "$CONFIG_DIR"
# 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" # 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 $1 = /path/to/steam-launch-wrapper
MSI rollback and removes all installed files. Bypass it by extracting on Linux: $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 ```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" \ docker cp "$WOLF_CONTAINER:/home/retro/.steam/steam/steamapps/compatdata/1237950/pfx/drive_c/ea_app.msi" \
/tmp/ea_app.msi /tmp/ea_app.msi
# Extract (msitools package) # Extract on host (bypasses JunoConfigureRegistry entirely)
sudo apt-get install -y msitools sudo apt-get install -y msitools
mkdir -p /tmp/ea_app_extracted mkdir -p /tmp/ea_app_extracted
msiextract -C /tmp/ea_app_extracted /tmp/ea_app.msi 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" 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 " docker exec "$WOLF_CONTAINER" bash -c "
[ -L '$PFXBASE/EA Desktop' ] && rm '$PFXBASE/EA Desktop' [ -L '$PFXBASE/EA Desktop' ] && rm '$PFXBASE/EA Desktop'
mkdir -p '$PFXBASE/14.2.0.3345' mkdir -p '$PFXBASE/14.2.0.3345'
ln -s 14.2.0.3345 '$PFXBASE/EA Desktop' 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/." \ docker cp "/tmp/ea_app_extracted/Electronic Arts/EA Desktop/EA Desktop/." \
"$WOLF_CONTAINER:$PFXBASE/14.2.0.3345/" "$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 ## Troubleshooting
### "link2ea not found" / game exits in ~6 seconds ### Game exits in ~6 seconds, no popup
EA Desktop files are missing or in wrong path. Check: Check wrapper log inside container:
```bash ```bash
docker exec "$WOLF_CONTAINER" find \ docker exec "$WOLF_CONTAINER" bash -c "
"/home/retro/.steam/steam/steamapps/compatdata/1237950/pfx/drive_c/Program Files/Electronic Arts" \ cat /tmp/ea_install.log | tail -20
-name "Link2EA.exe" 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) ### Wrapper never runs (Steam ignores launch options)
Steam wrote config before chmod 555 was applied. Kill Steam, chmod 555 the directory, Steam wrote config before chmod 555 was applied. Kill Steam, verify chmod 555 is set
then edit localconfig.vdf. Steam reads config fresh on startup. on the config directory, edit localconfig.vdf, then start Steam again.
### 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 56) 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.
### localconfig.vdf gets overwritten on Steam shutdown ### localconfig.vdf gets overwritten on Steam shutdown
Steam uses atomic rename (temp file + rename into place). `chmod 444` on the file `chmod 555` on the directory (not the file) prevents the atomic rename Steam uses.
is bypassed by the rename. Solution: `chmod 555` on the **directory** containing
localconfig.vdf — this prevents new files being renamed into the directory. ### 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 | | Path | Description |
|------|-------------| |------|-------------|
| `/home/retro/.steam/steam/steamapps/compatdata/1237950/pfx/` | SWBF2 Wine prefix | | `/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/system.reg` | Wine HKLM registry (plain text) |
| `/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/ea_app.msi` | EA App MSI (~227 MB, appears after first launch) |
| `/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/common/STAR WARS Battlefront II/starwarsbattlefrontii.exe` | Actual game binary |
| `/home/retro/.steam/steam/userdata/<uid>/config/localconfig.vdf` | Steam per-user config (launch options) | | `/home/retro/.steam/steam/userdata/<uid>/config/localconfig.vdf` | Steam per-user config (launch options) |
| `/home/retro/ea_install.sh` | Launch wrapper script | | `/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) |