From ddf481b72fe61f00bdddce480ee22d7d0ce12bf1 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 21 Jun 2026 18:50:22 +0000 Subject: [PATCH] wolf: add install-ea-app and diagnose-ea, fix link2ea registration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit install-ea-app: runs EAappInstaller.exe inside the WolfSteam container using GE-Proton's wine binary. The container has a virtual display so the EA App installer GUI appears in Moonlight; the user clicks through it and logs in to their EA account. After EA App installs, fix-ea-game registers the link2ea:// handler and clears the install-script loop. diagnose-ea: prints the current link2ea:// registry state from both system.reg and user.reg, locates EADesktop.exe/Link2EA.exe, shows StateFlags, and tails the relevant Proton log lines — the first thing to run when the game returns straight to the Play screen. _apply_ea_fix: now checks user.reg as well as system.reg for an existing link2ea:// registration (GE-Proton writes to user.reg during prefix setup); also searches for Link2EA.exe as a fallback handler when EADesktop.exe is not yet installed; reports a clear next step when neither is found. Co-Authored-By: Claude Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs --- services/wolf.sh | 285 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 241 insertions(+), 44 deletions(-) diff --git a/services/wolf.sh b/services/wolf.sh index 61fa571..076dc25 100644 --- a/services/wolf.sh +++ b/services/wolf.sh @@ -1032,18 +1032,33 @@ _apply_ea_fix() { sleep 2 fi - # Locate EADesktop.exe inside the Proton prefix (EA App installs here after - # EAappInstaller finishes — it runs async so may appear after first Play). + # Locate EA App executables inside the Proton prefix. + # Prefer EADesktop.exe (full EA App install); fall back to Link2EA.exe (stub or partial). local pfx_root pfx_root="$steam_home/.steam/steam/steamapps/compatdata/$appid/pfx/drive_c" - local ea_exe - ea_exe=$(sudo find "$pfx_root" -maxdepth 6 \ + local ureg + ureg="$steam_home/.steam/steam/steamapps/compatdata/$appid/pfx/user.reg" + local ea_exe link2ea_exe + ea_exe=$(sudo find "$pfx_root" -maxdepth 8 \ -ipath "*/Electronic Arts/EA Desktop/EA Desktop/EADesktop.exe" \ -print -quit 2>/dev/null) + link2ea_exe=$(sudo find "$pfx_root" -maxdepth 8 \ + -ipath "*/Electronic Arts/EA Desktop/*/EA Desktop/Link2EA.exe" \ + -print -quit 2>/dev/null) - if sudo grep -q 'EADesktopSetup' "$reg" 2>/dev/null && \ - sudo grep -q 'link2ea' "$reg" 2>/dev/null; then + # check both system.reg AND user.reg for existing link2ea registration + local _has_link2ea=0 + { sudo grep -q 'link2ea' "$reg" 2>/dev/null || sudo grep -q 'link2ea' "$ureg" 2>/dev/null; } \ + && _has_link2ea=1 + + if sudo grep -q 'EADesktopSetup' "$reg" 2>/dev/null && [ "$_has_link2ea" = 1 ]; then echo "Registry keys already present in AppID $appid prefix." + if [ -n "$ea_exe" ]; then + echo " EA App: $ea_exe" + elif [ -n "$link2ea_exe" ]; then + echo " Link2EA.exe: $link2ea_exe" + echo " NOTE: Full EA App not yet installed. Run ./manage.sh install-ea-app to install it." + fi else echo "Patching EA install-script markers for AppID $appid..." # Wine v2 registry format uses doubled backslashes as path separator. @@ -1055,14 +1070,25 @@ _apply_ea_fix() { printf '\n[Software\\\\Valve\\\\Steam\\\\Apps\\\\%s] 1781772837\n"EADesktopSetup"=dword:00000001\n' "$appid" printf '\n[Software\\\\Wow6432Node\\\\Valve\\\\Steam\\\\Apps\\\\%s] 1781772837\n"EADesktopSetup"=dword:00000001\n' "$appid" - # Register the link2ea:// URL protocol so SWBF2 can hand off to EA App. - # SWBF2 calls ShellExecute("link2ea://launchgame/...") and exits; without - # this handler Wine returns error 31 and the game never gets past the - # launch screen. + # Register the link2ea:// URL protocol handler in system.reg (HKLM). + # SWBF2 calls ShellExecute("link2ea://launchgame/...") and exits; the + # EA App (EADesktop.exe) re-authenticates and re-launches the game. + # GE-Proton's steam.exe intercepts link2ea:// and forwards to Link2EA.exe. + # NOTE: user.reg (HKCU) takes priority; GE-Proton may already have registered + # this there during prefix setup. Check with: ./manage.sh diagnose-ea + local _handler_exe="" if [ -n "$ea_exe" ]; then - # Convert absolute host path to a Wine drive_c–relative Windows path. + _handler_exe="$ea_exe" + echo " Using real EA App: $ea_exe" + elif [ -n "$link2ea_exe" ]; then + _handler_exe="$link2ea_exe" + echo " Using Link2EA.exe stub: $link2ea_exe" + echo " NOTE: Run ./manage.sh install-ea-app to install full EA App." + fi + + if [ -n "$_handler_exe" ]; then local win_path - win_path=$(echo "$ea_exe" \ + win_path=$(echo "$_handler_exe" \ | sed "s|$pfx_root||" \ | sed 's|/|\\\\|g' \ | sed 's|^|C:|') @@ -1074,14 +1100,15 @@ _apply_ea_fix() { printf '\n[Software\\\\Wow6432Node\\\\Classes\\\\link2ea\\\\shell] 1781772837\n' printf '\n[Software\\\\Wow6432Node\\\\Classes\\\\link2ea\\\\shell\\\\open] 1781772837\n' printf '\n[Software\\\\Wow6432Node\\\\Classes\\\\link2ea\\\\shell\\\\open\\\\command] 1781772837\n@="%s \\"%%1\\""\n' "$win_path" - echo " link2ea:// handler registered → $win_path" + echo " link2ea:// handler registered in system.reg → $win_path" else - echo " WARNING: EADesktop.exe not found yet — link2ea:// handler NOT registered." - echo " Run './manage.sh wait-ea-app $appid' after clicking Play once" - echo " to wait for EAappInstaller to finish and then register the handler." + echo " WARNING: EA App not found (neither EADesktop.exe nor Link2EA.exe)." + echo " link2ea:// handler NOT registered in system.reg." + echo " GE-Proton may have already registered it in user.reg — check with:" + echo " ./manage.sh diagnose-ea $appid" + echo " To install EA App: ./manage.sh install-ea-app $appid" fi } | sudo tee -a "$reg" >/dev/null - # Keep the prefix owned by the in-container user or Wine rejects it. sudo chown 1000:1000 "$reg" echo " Registry patched." fi @@ -1854,6 +1881,169 @@ PYEOF echo "Applying full EA fix (includes link2ea:// handler)..." _apply_ea_fix "$_wea_appid" ;; + install-ea-app) + # Run EAappInstaller.exe INSIDE the WolfSteam container using GE-Proton's + # wine binary so it sees a virtual display and can complete its GUI. + # + # Usage: ./manage.sh install-ea-app [AppID] + # + # Workflow: + # 1. Start Wolf and open Steam in Moonlight: ./manage.sh start + # 2. From a terminal/SSH: ./manage.sh install-ea-app + # 3. Watch Moonlight — the EA App installer window appears; click through it + # 4. Log in to your EA account when prompted + # 5. After EA App installs, run: ./manage.sh fix-ea-game + # 6. Click Play on the game — it should launch via EA App now + _ia_appid="${2:-1237950}" + _ia_steam_home=$(_steam_home) + if [ -z "$_ia_steam_home" ]; then + echo "No Steam home found. Start Wolf and open the Steam app in Moonlight first." + exit 1 + fi + _ia_container=$(docker ps --format '{{.Names}}' | grep -i WolfSteam | head -1) + if [ -z "$_ia_container" ]; then + echo "WolfSteam container is not running." + echo " Start Wolf: ./manage.sh start" + echo " Open the Steam app in Moonlight, wait for Steam to load, then re-run." + exit 1 + fi + # Find EAappInstaller bundled with the game + _ia_installer_host=$(sudo find \ + "$_ia_steam_home/.steam/steam/steamapps" -maxdepth 12 \ + -name "EAappInstaller.exe" -print -quit 2>/dev/null) + if [ -z "$_ia_installer_host" ]; then + echo "EAappInstaller.exe not found. Make sure the game (AppID $_ia_appid) is installed." + exit 1 + fi + # Container mounts the session home at /home/retro — translate paths + _ia_installer_container="${_ia_installer_host/#$_ia_steam_home//home/retro}" + # Find GE-Proton inside the container + _ia_gep=$(docker exec -u 1000 "$_ia_container" bash -c \ + 'ls /home/retro/.steam/compatibilitytools.d/ 2>/dev/null | grep -i GE-Proton | sort -V | tail -1' 2>/dev/null) + if [ -z "$_ia_gep" ]; then + echo "GE-Proton not found inside the container." + echo " Install it: ./manage.sh ge-proton" + echo " Then open Steam in Moonlight, set the game to use GE-Proton in Compatibility," + echo " click Play once to create the prefix, and re-run this command." + exit 1 + fi + _ia_wine="/home/retro/.steam/compatibilitytools.d/$_ia_gep/files/bin/wine" + _ia_wineprefix="/home/retro/.steam/steam/steamapps/compatdata/$_ia_appid/pfx" + _ia_display=$(docker exec "$_ia_container" printenv DISPLAY 2>/dev/null) + _ia_display="${_ia_display:-:0}" + echo "Installing EA App inside the WolfSteam container..." + echo " Container: $_ia_container" + echo " GE-Proton: $_ia_gep" + echo " Installer: $_ia_installer_container" + echo " Display: $_ia_display" + echo "" + echo "IMPORTANT: The EA App installer window will appear in Moonlight." + echo " Click through it and log in to your EA account." + echo " This may take 2-10 minutes." + echo "" + # Launch the installer inside the container (background so we can poll) + docker exec -u 1000 \ + -e DISPLAY="$_ia_display" \ + -e WINEPREFIX="$_ia_wineprefix" \ + -e WINE_LARGE_ADDRESS_AWARE=1 \ + -e WINEDEBUG="fixme-all" \ + "$_ia_container" \ + "$_ia_wine" "$_ia_installer_container" & + _ia_bg_pid=$! + # Poll on the HOST for EADesktop.exe to appear (up to 15 min) + _ia_pfx_host="$_ia_steam_home/.steam/steam/steamapps/compatdata/$_ia_appid/pfx/drive_c" + _ia_found=0 + for _ia_i in $(seq 1 60); do + _ia_exe=$(sudo find "$_ia_pfx_host" -maxdepth 8 \ + -ipath "*/Electronic Arts/EA Desktop/EA Desktop/EADesktop.exe" \ + -print -quit 2>/dev/null) + if [ -n "$_ia_exe" ]; then + _ia_found=1 + echo "" + echo "EA App installed at: $_ia_exe" + break + fi + # If wine process has already exited, do one final check + if ! kill -0 "$_ia_bg_pid" 2>/dev/null && [ "$_ia_i" -gt 1 ]; then + echo "" + echo "Wine process exited. Doing final check..." + _ia_exe=$(sudo find "$_ia_pfx_host" -maxdepth 8 \ + -ipath "*/Electronic Arts/EA Desktop/EA Desktop/EADesktop.exe" \ + -print -quit 2>/dev/null) + if [ -n "$_ia_exe" ]; then + _ia_found=1 + echo "EA App installed at: $_ia_exe" + else + echo "EA App not found after installer exited." + echo "The installer may have failed or exited early." + echo "Check: ./manage.sh diagnose-ea $_ia_appid" + fi + break + fi + printf "\r Waiting for EA App to install... (%ds elapsed)" "$((_ia_i * 15))" + sleep 15 + done + kill "$_ia_bg_pid" 2>/dev/null || true + if [ "$_ia_found" = 1 ]; then + echo "Applying EA fix (registering link2ea:// handler)..." + _apply_ea_fix "$_ia_appid" + echo "" + echo "Next: Click Play on the game in Steam. EA App should authenticate and launch it." + else + echo "" + echo "EA App did not finish installing within 15 minutes." + echo " • Did the installer window appear in Moonlight?" + echo " • Try running ./manage.sh diagnose-ea $_ia_appid for current state" + echo " • If the installer appeared but failed: check the EA App website for a newer installer" + exit 1 + fi + ;; + diagnose-ea) + # Show the current state of the EA App / link2ea:// setup for debugging. + # Run this after ./manage.sh fix-ea-game to verify the registry is correct, + # or when troubleshooting why an EA game returns to the Play screen. + # + # Usage: ./manage.sh diagnose-ea [AppID] + _dx_appid="${2:-1237950}" + _dx_sh=$(_steam_home) + _dx_pfx="$_dx_sh/.steam/steam/steamapps/compatdata/$_dx_appid/pfx" + _dx_acf="$_dx_sh/.steam/steam/steamapps/appmanifest_${_dx_appid}.acf" + echo "=== EA Diagnostic — AppID $_dx_appid ===" + echo "Prefix: $_dx_pfx" + echo "" + echo "--- system.reg: link2ea entries ---" + sudo grep -i -A3 "link2ea" "$_dx_pfx/system.reg" 2>/dev/null || echo "(none in system.reg)" + echo "" + echo "--- user.reg: link2ea entries ---" + sudo grep -i -A3 "link2ea" "$_dx_pfx/user.reg" 2>/dev/null || echo "(none in user.reg)" + echo "" + echo "--- EA App executables in prefix ---" + _dx_desktop=$(sudo find "$_dx_pfx/drive_c" -maxdepth 8 -iname "EADesktop.exe" -print 2>/dev/null) + _dx_link2ea=$(sudo find "$_dx_pfx/drive_c" -maxdepth 8 -iname "Link2EA.exe" -print 2>/dev/null) + echo "EADesktop.exe: ${_dx_desktop:-(not found)}" + echo "Link2EA.exe: ${_dx_link2ea:-(not found)}" + echo "" + echo "--- system.reg: InstallSuccessful ---" + sudo grep -i "InstallSuccessful" "$_dx_pfx/system.reg" 2>/dev/null | head -5 \ + || echo "(none)" + echo "" + echo "--- AppManifest StateFlags ---" + if [ -f "$_dx_acf" ]; then + grep "StateFlags" "$_dx_acf" + else + echo "(acf not found at $_dx_acf)" + fi + echo "" + echo "--- Recent Proton log entries (errors + EA-related) ---" + _dx_log="$_dx_sh/steam-${_dx_appid}.log" + if [ -f "$_dx_log" ]; then + grep -i "link2ea\|EA Desktop\|run_process\|ShellExecute\|err:" "$_dx_log" 2>/dev/null \ + | grep -v "mscoree\|seh_unwind\|loaddll\|fixme" | tail -20 + else + echo "(no log yet — launch the game once to generate it)" + echo "Expected path: $_dx_log" + fi + ;; 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 @@ -1888,8 +2078,8 @@ 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 fix-perms - install-completion backup" + add-web ge-proton games fix-ea-game wait-ea-app + install-ea-app diagnose-ea fix-perms install-completion backup" COMPREPLY=( $(compgen -W "$commands" -- "$cur") ) } # Register for both 'manage.sh' and './manage.sh' invocation styles @@ -1945,8 +2135,10 @@ 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 fix-ea-game [appid] - Apply EA fix directly (default: SWBF2 1237950) - ./manage.sh wait-ea-app [appid] - Watch for EA App to install, then register link2ea:// handler" + 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)" + echo " ./manage.sh diagnose-ea [appid] - Show link2ea:// registry state and Proton log" echo " ./manage.sh fix-perms - Fix 'Permission denied' app startup errors" echo " ./manage.sh install-completion - Enable tab-completion for this script" echo " ./manage.sh backup - How to set up backups" @@ -2284,12 +2476,16 @@ PYEOF echo "" echo "── EA GAMES (Battlefront II, etc.) ───────────────────" echo "" - echo " EA titles need GE-Proton + an install-script unstick:" + echo " EA titles need GE-Proton + a full EA App install:" echo " 1. ./manage.sh ge-proton # install GE-Proton once" echo " 2. In Steam: game → Properties → Compatibility → Force GE-Proton" - echo " 3. Click Play once (builds the Proton prefix; will hang — that's ok)" - echo " 4. ./manage.sh games # pick the game's number to fix it" - echo " 5. Cancel the 'installing' screen in Steam, Play again — it launches" + echo " 3. Click Play once (builds the Proton prefix; hang is expected)" + echo " 4. ./manage.sh install-ea-app # runs EA App installer in the container" + echo " (watch Moonlight — an installer window appears; click through + log in)" + echo " 5. ./manage.sh fix-ea-game # unstick the install-script loop" + echo " 6. Click Play — EA App authenticates and launches the game" + echo "" + echo " Diagnose: ./manage.sh diagnose-ea # check link2ea:// registry state" echo "" echo "── BACKUPS ───────────────────────────────────────────" echo "" @@ -2341,6 +2537,8 @@ cd $WOLF_DIR ./manage.sh ge-proton # install GE-Proton (needed for EA games) ./manage.sh games # list installed games + their AppIDs ./manage.sh fix-ea-game # unstick the EA App install loop for a game +./manage.sh install-ea-app # install EA App inside the container (GUI in Moonlight) +./manage.sh diagnose-ea # check link2ea:// state when game returns to Play ./manage.sh install-completion # enable tab-completion for manage.sh \`\`\` @@ -2349,34 +2547,33 @@ Run \`./manage.sh install-completion\` once, then re-open your shell (or \`source ~/.bashrc\`). After that, \`./manage.sh \` lists all commands. ## EA games (Battlefront II 2017, etc.) -EA titles bundle an EA App bootstrapper that hangs forever under stock Proton -in a container — the game sits on **"running install script (EA app)"** and -never starts. Two things fix it: GE-Proton (not in Steam's built-in Proton -list) and pre-satisfying the install-script markers in the game's prefix. +EA titles require GE-Proton and the EA App to be installed inside the Wine +prefix. The EA App handles authentication — without it, the game launches +and immediately returns to the Play screen. \`\`\`bash cd $WOLF_DIR -./manage.sh ge-proton # 1. install GE-Proton once -# 2. Steam → game → Properties → -# Compatibility → Force GE-Proton -# 3. Click Play once (builds the prefix; -# it will hang — that's expected) -./manage.sh games # 4. lists games numbered; enter the -# game's number to apply the EA fix -# 5. Cancel the 'installing' screen, -# Play again — it launches. +./manage.sh ge-proton # 1. install GE-Proton once +# 2. Steam → game → Properties → +# Compatibility → Force GE-Proton +# 3. Click Play once (builds the prefix; +# it will hang — that's expected) +./manage.sh install-ea-app # 4. runs EA App installer INSIDE the container +# (watch Moonlight — installer GUI appears; +# click through it and log in to EA account) +./manage.sh fix-ea-game # 5. unstick the install-script loop +# 6. Click Play — EA App authenticates + launches \`\`\` -\`games\` lists each installed game with a number and AppID, then asks which -one to fix — just type the number. (\`fix-ea-game [appid]\` does the same thing -non-interactively, defaulting to SWBF2 2017's \`1237950\`.) +**Troubleshooting**: If the game returns straight to the Play screen after step 6: +\`\`\`bash +./manage.sh diagnose-ea # shows link2ea:// registry state + Proton log +\`\`\` Notes: - Steam **AppIDs are global** — SWBF2 (2017) is always \`1237950\` on every machine — but you don't need to know it; the \`games\` picker handles it. -- The fix is safe and opt-in: it only touches the game you pick, only if its - Proton prefix exists, and is idempotent. The EA Desktop "installed" marker is - shared across all EA titles, so the same fix works for any EA game. +- \`fix-ea-game\` is idempotent and only touches the game you pick. - \`ge-proton\` takes an optional version to pin, e.g. \`./manage.sh ge-proton GE-Proton10-34\`.