The MSI is bundled in steamapps/common with the game files. The script was only checking drive_c (where Steam copies it after a launch), causing a false "not found" error before the user had launched the game. Now searches steamapps/common and all of steamapps as fallbacks, reports which path it found the MSI at. Also remove stale references to the "Origin is not installed" error which no longer appears. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
305 lines
12 KiB
Bash
Executable File
305 lines
12 KiB
Bash
Executable File
#!/bin/bash
|
|
# setup-swbf2-linux.sh — Fix Star Wars Battlefront II (2017, AppID 1237950)
|
|
# for native Linux Steam with GE-Proton (no Wolf / no Docker).
|
|
#
|
|
# What this does:
|
|
# 1. Extracts EA Desktop from the bundled ea_app.msi using msiextract —
|
|
# bypasses JunoConfigureRegistry, a .NET custom action Wine cannot run,
|
|
# which causes the full MSI installer to roll back.
|
|
# 2. Copies EA Desktop files (Link2EA.exe, EALocalHostSvc.exe, etc.) into the
|
|
# game's Wine prefix.
|
|
# 3. Writes link2ea_fix.reg and ea_services.reg into drive_c so they survive
|
|
# Wine prefix operations.
|
|
# 4. Installs a launch wrapper that imports the .reg files via Proton's own
|
|
# wine binary on every launch — required because direct edits to system.reg
|
|
# are overwritten when wineserver flushes to disk on shutdown.
|
|
# 5. Sets Steam launch options for SWBF2.
|
|
#
|
|
# Prerequisites — do these BEFORE running this script:
|
|
# a. GE-Proton10-34 (or later) installed via ProtonUp-Qt or manually.
|
|
# In Steam: SWBF2 → Properties → Compatibility → Force GE-Proton.
|
|
# b. msitools installed:
|
|
# sudo apt-get install -y msitools # Debian/Ubuntu
|
|
# sudo dnf install -y msitools # Fedora
|
|
# c. Launch SWBF2 once — wait ~10 seconds for the "Origin is not installed"
|
|
# error, then close it. This creates the Wine prefix and drops ea_app.msi.
|
|
# d. Your EA account is linked to your Steam account at ea.com (one-time;
|
|
# persists on EA's servers across reinstalls).
|
|
#
|
|
# After this script completes:
|
|
# Launch SWBF2. Let Vulkan shaders compile on first run (several minutes,
|
|
# only once). EA App authenticates via your linked Steam/EA account.
|
|
#
|
|
# Usage:
|
|
# chmod +x setup-swbf2-linux.sh
|
|
# ./setup-swbf2-linux.sh
|
|
|
|
set -euo pipefail
|
|
|
|
APPID="1237950"
|
|
WRAPPER_PATH="$HOME/.local/bin/ea_install.sh"
|
|
GE_PROTON_VERSION="GE-Proton10-34"
|
|
|
|
echo "=== SWBF2 (2017) Linux Steam Setup ==="
|
|
echo ""
|
|
|
|
# ── Locate Steam home ───────────────────────────────────────────────────────
|
|
find_steam_home() {
|
|
for candidate in \
|
|
"$HOME/.steam/steam" \
|
|
"$HOME/.local/share/Steam" \
|
|
"$HOME/.var/app/com.valvesoftware.Steam/.steam/steam"; do
|
|
if [ -d "$candidate/steamapps" ]; then
|
|
echo "$candidate"
|
|
return 0
|
|
fi
|
|
done
|
|
return 1
|
|
}
|
|
|
|
STEAM_HOME=$(find_steam_home) || {
|
|
echo "ERROR: Steam home not found. Is Steam installed and have you launched it at least once?"
|
|
exit 1
|
|
}
|
|
echo "Steam home: $STEAM_HOME"
|
|
|
|
# ── Install GE-Proton if not present ───────────────────────────────────────
|
|
GEP_DIR="$HOME/.steam/root/compatibilitytools.d"
|
|
mkdir -p "$GEP_DIR"
|
|
if [ -d "$GEP_DIR/$GE_PROTON_VERSION" ]; then
|
|
echo "GE-Proton: $GE_PROTON_VERSION already installed"
|
|
else
|
|
echo "Installing $GE_PROTON_VERSION..."
|
|
GEP_URL="https://github.com/GloriousEggroll/proton-ge-custom/releases/download/$GE_PROTON_VERSION/$GE_PROTON_VERSION.tar.gz"
|
|
GEP_TMP="/tmp/$GE_PROTON_VERSION.tar.gz"
|
|
if ! curl -L --progress-bar -o "$GEP_TMP" "$GEP_URL"; then
|
|
echo "ERROR: Download failed. Check your internet connection and try again."
|
|
exit 1
|
|
fi
|
|
tar -xzf "$GEP_TMP" -C "$GEP_DIR"
|
|
rm -f "$GEP_TMP"
|
|
echo "GE-Proton installed to: $GEP_DIR/$GE_PROTON_VERSION"
|
|
echo ""
|
|
echo "IMPORTANT: Restart Steam now, then:"
|
|
echo " Right-click SWBF2 → Properties → Compatibility"
|
|
echo " → Force a specific Steam Play compatibility tool → $GE_PROTON_VERSION"
|
|
echo "Then re-run this script."
|
|
echo ""
|
|
read -rp "Press Enter after you have restarted Steam and set GE-Proton, or Ctrl+C to abort..."
|
|
fi
|
|
|
|
PFX_C="$STEAM_HOME/steamapps/compatdata/$APPID/pfx/drive_c"
|
|
MSI="$PFX_C/ea_app.msi"
|
|
|
|
# ── Step 1: verify Wine prefix exists ──────────────────────────────────────
|
|
echo ""
|
|
if [ ! -d "$PFX_C" ]; then
|
|
echo "ERROR: Wine prefix not found at $PFX_C"
|
|
echo ""
|
|
echo "Required before running this script:"
|
|
echo " 1. In Steam: right-click SWBF2 → Properties → Compatibility"
|
|
echo " → Force GE-Proton10-34 (or later)"
|
|
echo " 2. Click Play on SWBF2 — wait ~10 seconds then close it"
|
|
echo " 3. Re-run this script"
|
|
exit 1
|
|
fi
|
|
echo "[1/6] Wine prefix: OK"
|
|
|
|
# ── Step 2: locate ea_app.msi ──────────────────────────────────────────────
|
|
# The MSI is bundled with the game files. Steam may also copy it to drive_c
|
|
# when the install script runs. Check both locations.
|
|
if [ ! -f "$MSI" ]; then
|
|
GAME_DIR=$(find "$STEAM_HOME/steamapps/common" -maxdepth 2 \
|
|
-name "ea_app.msi" 2>/dev/null | head -1)
|
|
if [ -n "$GAME_DIR" ]; then
|
|
echo "Found ea_app.msi in game files: $GAME_DIR"
|
|
MSI="$GAME_DIR"
|
|
fi
|
|
fi
|
|
if [ ! -f "$MSI" ]; then
|
|
# Also search anywhere under steamapps
|
|
MSI_FOUND=$(find "$STEAM_HOME/steamapps" -name "ea_app.msi" 2>/dev/null | head -1)
|
|
[ -n "$MSI_FOUND" ] && MSI="$MSI_FOUND"
|
|
fi
|
|
if [ ! -f "$MSI" ]; then
|
|
echo ""
|
|
echo "ERROR: ea_app.msi not found."
|
|
echo ""
|
|
echo "Launch SWBF2 once from Steam (with GE-Proton set in Compatibility),"
|
|
echo "wait ~10 seconds for it to attempt startup, then close it and re-run."
|
|
echo ""
|
|
echo "If you just installed the game, verify it downloaded fully in Steam."
|
|
exit 1
|
|
fi
|
|
MSI_SIZE=$(stat -c%s "$MSI")
|
|
if [ "$MSI_SIZE" -lt 50000000 ]; then
|
|
echo "WARNING: ea_app.msi is only $MSI_SIZE bytes (expected ~227 MB)."
|
|
echo "It may still be downloading. Wait a moment and re-run."
|
|
exit 1
|
|
fi
|
|
echo "[2/6] ea_app.msi ($(( MSI_SIZE / 1048576 )) MB): OK ($MSI)"
|
|
|
|
# ── Step 3: extract MSI on the host ────────────────────────────────────────
|
|
echo "[3/6] Extracting EA Desktop files from MSI (~30s)..."
|
|
if ! command -v msiextract >/dev/null 2>&1; then
|
|
echo "msitools not found — installing..."
|
|
if command -v apt-get >/dev/null 2>&1; then
|
|
sudo apt-get install -y msitools
|
|
elif command -v dnf >/dev/null 2>&1; then
|
|
sudo dnf install -y msitools
|
|
elif command -v pacman >/dev/null 2>&1; then
|
|
sudo pacman -S --noconfirm msitools
|
|
else
|
|
echo "ERROR: Cannot auto-install msitools — package manager not recognised."
|
|
echo "Install msitools manually and re-run."
|
|
exit 1
|
|
fi
|
|
fi
|
|
EXTRACT_DIR="/tmp/ea_app_extracted_$$"
|
|
rm -rf "$EXTRACT_DIR"
|
|
mkdir -p "$EXTRACT_DIR"
|
|
if ! msiextract -C "$EXTRACT_DIR" "$MSI" >/dev/null 2>&1; then
|
|
echo "ERROR: msiextract failed. Check that msitools is properly installed."
|
|
rm -rf "$EXTRACT_DIR"
|
|
exit 1
|
|
fi
|
|
EA_SRC=$(find "$EXTRACT_DIR" -maxdepth 5 \
|
|
-path "*/Electronic Arts/EA Desktop/EA Desktop" -type d 2>/dev/null | head -1)
|
|
if [ -z "$EA_SRC" ] || [ ! -f "$EA_SRC/Link2EA.exe" ]; then
|
|
echo "ERROR: Link2EA.exe not found after extraction. MSI structure may have changed."
|
|
ls -la "$EXTRACT_DIR/Electronic Arts/EA Desktop/" 2>/dev/null || true
|
|
rm -rf "$EXTRACT_DIR"
|
|
exit 1
|
|
fi
|
|
echo " $(ls "$EA_SRC" | wc -l) files extracted including Link2EA.exe"
|
|
|
|
# ── Step 4: copy EA Desktop files into Wine prefix ─────────────────────────
|
|
echo "[4/6] Installing EA Desktop files into Wine prefix..."
|
|
EA_DEST_BASE="$PFX_C/Program Files/Electronic Arts/EA Desktop"
|
|
|
|
# Use the version from a broken symlink left by a failed install, or default.
|
|
EA_VERSION="14.2.0.3345"
|
|
if [ -L "$EA_DEST_BASE/EA Desktop" ]; then
|
|
_linked=$(readlink "$EA_DEST_BASE/EA Desktop" 2>/dev/null || true)
|
|
[ -n "$_linked" ] && EA_VERSION="$_linked"
|
|
fi
|
|
|
|
EA_DEST="$EA_DEST_BASE/$EA_VERSION"
|
|
mkdir -p "$EA_DEST"
|
|
cp -r "$EA_SRC/." "$EA_DEST/"
|
|
|
|
# Remove any stale symlink, then create a clean one
|
|
rm -f "$EA_DEST_BASE/EA Desktop"
|
|
ln -sf "$EA_VERSION" "$EA_DEST_BASE/EA Desktop"
|
|
|
|
if [ ! -f "$EA_DEST/Link2EA.exe" ]; then
|
|
echo "ERROR: Copy failed — Link2EA.exe not found at $EA_DEST/Link2EA.exe"
|
|
rm -rf "$EXTRACT_DIR"
|
|
exit 1
|
|
fi
|
|
echo " EA Desktop $EA_VERSION installed"
|
|
rm -rf "$EXTRACT_DIR"
|
|
|
|
# ── Step 5: write .reg files and launch wrapper ─────────────────────────────
|
|
echo "[5/6] Writing registry fix files and launch wrapper..."
|
|
|
|
# link2ea:// protocol handler — tells Wine how to find Link2EA.exe.
|
|
# GE-Proton's steam.exe intercepts link2ea:// URLs and uses this handler
|
|
# to launch Link2EA.exe, which hands off to EA Desktop for authentication.
|
|
cat > "$PFX_C/link2ea_fix.reg" << '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 Windows services — EALocalHostSvc provides local IPC that Link2EA.exe
|
|
# needs. Without it launch fails with RPC_S_SERVER_UNAVAILABLE (0x800706ba).
|
|
cat > "$PFX_C/ea_services.reg" << '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
|
|
|
|
# Launch wrapper. Runs regedit through Proton's launch chain on every launch
|
|
# so registry entries survive wineserver restarts. Direct edits to system.reg
|
|
# are overwritten when wineserver flushes to disk on shutdown.
|
|
mkdir -p "$HOME/.local/bin"
|
|
cat > "$WRAPPER_PATH" << '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 "$WRAPPER_PATH"
|
|
echo " .reg files written, wrapper installed at $WRAPPER_PATH"
|
|
|
|
# ── Step 6: set launch options in localconfig.vdf ──────────────────────────
|
|
echo "[6/6] Setting Steam launch options..."
|
|
STEAM_UID=$(ls "$STEAM_HOME/userdata/" 2>/dev/null | head -1)
|
|
if [ -z "$STEAM_UID" ]; then
|
|
echo "WARNING: No Steam userdata found. Sign in to Steam first, then re-run."
|
|
echo " Or set launch options manually — see below."
|
|
else
|
|
CFG_FILE="$STEAM_HOME/userdata/$STEAM_UID/config/localconfig.vdf"
|
|
if [ ! -f "$CFG_FILE" ]; then
|
|
echo "WARNING: localconfig.vdf not found. Launch Steam first, then re-run."
|
|
else
|
|
LAUNCH_OPT="$WRAPPER_PATH %command%"
|
|
python3 - "$CFG_FILE" "$LAUNCH_OPT" << 'PYEOF'
|
|
import sys, re
|
|
path, opt = sys.argv[1], sys.argv[2]
|
|
with open(path) as f:
|
|
c = f.read()
|
|
new = re.sub(r'("1237950".*?"LaunchOptions"\s*)"[^"]*"', rf'\1"{opt}"', c, flags=re.DOTALL)
|
|
if new == c:
|
|
new = re.sub(r'("1237950"\s*\n\s*\{)', rf'\1\n\t\t\t\t"LaunchOptions"\t\t"{opt}"', c)
|
|
if new == c:
|
|
print("WARNING: 1237950 block not found — set launch options manually (see below).")
|
|
sys.exit(0)
|
|
with open(path, 'w') as f:
|
|
f.write(new)
|
|
print(" LaunchOptions set.")
|
|
PYEOF
|
|
fi
|
|
fi
|
|
|
|
echo ""
|
|
echo "=== Setup complete ==="
|
|
echo ""
|
|
echo "Launch options set to: $WRAPPER_PATH %command%"
|
|
echo ""
|
|
echo "Next steps:"
|
|
echo " 1. Launch SWBF2 from Steam"
|
|
echo " 2. Let Vulkan shaders compile — do NOT skip (takes several minutes, once only)"
|
|
echo " 3. EA App authenticates automatically if your Steam and EA accounts are linked"
|
|
echo " 4. Game launches"
|
|
echo ""
|
|
echo "If launch options were not set automatically, set them in Steam:"
|
|
echo " Right-click SWBF2 → Properties → Launch Options:"
|
|
echo " $WRAPPER_PATH %command%"
|
|
echo ""
|
|
echo "Troubleshooting:"
|
|
echo " Wrapper log: tail /tmp/ea_install.log"
|
|
echo " Proton log: tail $STEAM_HOME/logs/steam_$APPID.log 2>/dev/null || \\"
|
|
echo " tail \$(ls -t $STEAM_HOME/steamapps/compatdata/$APPID/../../../steam-$APPID.log 2>/dev/null | head -1)"
|