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 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
12 KiB
Star Wars Battlefront II (2017) — Wolf/Moonlight Setup
AppID: 1237950
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
msitoolson the Docker host:sudo apt-get install -y msitools
The EA dependency problem
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
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.
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
Migrating to another machine:
# Back up the Wine prefix — EA credentials travel with it
tar -czf swbf2-prefix-backup.tar.gz \
/home/retro/.steam/steam/steamapps/compatdata/1237950/
Tokens last weeks to months before requiring re-login.
Why docker exec can't run Wine/Proton
docker exec carries high Linux capabilities (CapEff ≈ 0xa8ac35fb).
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
Only Steam itself can launch programs through sniper+GE-Proton. All Wine operations must go through Steam's launch chain — hence the wrapper approach.
How it works
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.
Steam → wrapper → regedit (registry fixes) → exec original args
→ GE-Proton steam.exe → link2ea:// → Link2EA.exe → EA Desktop → SWBF2
Step-by-step
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:
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:
WOLF_CONTAINER=$(docker ps --format '{{.Names}}' | grep Wolf)
docker cp "$WOLF_CONTAINER:/home/retro/.steam/steam/steamapps/compatdata/1237950/pfx/drive_c/ea_app.msi" \
/tmp/ea_app.msi
sudo apt-get install -y msitools
mkdir -p /tmp/ea_app_extracted
msiextract -C /tmp/ea_app_extracted /tmp/ea_app.msi
3. Copy EA Desktop files into the Wine prefix
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:
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")
PFXBASE="/home/retro/.steam/steam/steamapps/compatdata/1237950/pfx/drive_c/Program Files/Electronic Arts/EA Desktop"
docker exec "$WOLF_CONTAINER" bash -c "
rm -f '$PFXBASE/EA Desktop'
mkdir -p '$PFXBASE/$SYMLINK_TARGET'
ln -s '$SYMLINK_TARGET' '$PFXBASE/EA Desktop'
"
docker cp "/tmp/ea_app_extracted/Electronic Arts/EA Desktop/EA Desktop/." \
"$WOLF_CONTAINER:$PFXBASE/$SYMLINK_TARGET/"
# Verify
docker exec "$WOLF_CONTAINER" find "$PFXBASE" -name "Link2EA.exe"
4. Write registry fix files to drive_c
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).
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:
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
cat > /tmp/ea_install.sh << 'EOF'
#!/bin/bash
echo "=== launch $(date) ===" >> /tmp/ea_install.log
# 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
7. First launch
- Reconnect to Moonlight and launch SWBF2
- Let Vulkan shaders compile — do not skip, takes several minutes, only happens once
- EA App authenticates via your linked Steam/EA account (no manual login if accounts are linked)
- Game loads
Is this fragile? Will it work on a fresh install?
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 |
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.
The one irreducible manual step: Linking your EA account to Steam (done once at ea.com, persists across reinstalls via EA's servers).
Troubleshooting
"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.
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
docker exec "$WOLF_CONTAINER" bash -c "
tail -20 /tmp/ea_install.log
echo '---'
grep -E '(err:|link2ea|origin|RPC)' /home/retro/steam-1237950.log | tail -20
"
Key paths (inside WolfSteam container)
| 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 |
/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/<uid>/config/localconfig.vdf |
Steam launch options |
/home/retro/ea_install.sh |
Launch wrapper |
/tmp/ea_install.log |
Wrapper log (resets on container restart) |