Files
ubuntu-post-install/docs/SWBF2-2017-wolf-setup.md
T
Claude b756e7eedb 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 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-22 12:35:14 +00:00

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
  • msitools on 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

  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

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)