modified: README.md
new file: battlenet-diagnose.sh modified: battlenet-umu-setup.sh new file: battlenet-update-proton.sh
This commit is contained in:
@@ -8,18 +8,55 @@ A guide for installing the Battle.net launcher on Arch Linux (2026).
|
||||
|
||||
## TL;DR — Which method should I use?
|
||||
|
||||
| Method | Best for | Effort |
|
||||
|---|---|---|
|
||||
| **umu-launcher (standalone Proton, no Steam)** | Scripting, minimal installs, homelab. **Recommended.** | Low |
|
||||
| **Steam + Proton-GE (non-Steam shortcut)** | People who already run Steam. | Low |
|
||||
| **Lutris (official installer script)** | People who want a GUI game manager. | Low–Medium |
|
||||
| **Bottles (Flatpak, Gaming environment)** | Flatpak-first setups. | Low |
|
||||
| **Manual `wine-staging` prefix** | Pure-Wine purists, non-Proton setups. | High |
|
||||
| Method | Best for | Effort |
|
||||
| ---------------------------------------------- | ------------------------------------------------------ | ---------- |
|
||||
| **umu-launcher (standalone Proton, no Steam)** | Scripting, minimal installs, homelab. **Recommended.** | Low |
|
||||
| **Steam + Proton-GE (non-Steam shortcut)** | People who already run Steam. | Low |
|
||||
| **Lutris (official installer script)** | People who want a GUI game manager. | Low–Medium |
|
||||
| **Bottles (Flatpak, Gaming environment)** | Flatpak-first setups. | Low |
|
||||
| **Manual `wine-staging` prefix** | Pure-Wine purists, non-Proton setups. | High |
|
||||
|
||||
If you just want it to work: use **Method 1 (umu)**. It gives you Proton-grade compatibility without Steam, and the upstream protonfix for Battle.net automatically applies the workarounds you'd otherwise have to remember.
|
||||
|
||||
---
|
||||
|
||||
## Quick start — automated script
|
||||
|
||||
The fastest path is the included setup script, which handles everything in Method 1 automatically:
|
||||
|
||||
```bash
|
||||
# Download and run
|
||||
curl -LO https://raw.githubusercontent.com/your-repo/battlenet-umu-setup.sh
|
||||
chmod +x battlenet-umu-setup.sh
|
||||
./battlenet-umu-setup.sh
|
||||
```
|
||||
|
||||
Or if you already have this repo cloned:
|
||||
|
||||
```bash
|
||||
./battlenet-umu-setup.sh
|
||||
```
|
||||
|
||||
The script is idempotent — safe to re-run. Common flags:
|
||||
|
||||
```bash
|
||||
./battlenet-umu-setup.sh --yes # non-interactive / CI
|
||||
./battlenet-umu-setup.sh --reinstall # wipe prefix and start over
|
||||
./battlenet-umu-setup.sh --proton-version=GE-Proton9-20 # pin a specific Proton version
|
||||
./battlenet-umu-setup.sh --gpu=nvidia # override GPU auto-detection
|
||||
./battlenet-umu-setup.sh --prefix-dir=~/Games/bnet # custom prefix location
|
||||
./battlenet-umu-setup.sh --skip-packages # skip the package check
|
||||
```
|
||||
|
||||
Companion scripts also included:
|
||||
|
||||
| Script | Purpose |
|
||||
| ----------------------------- | ------------------------------------------------------------- |
|
||||
| `battlenet-update-proton.sh` | Download a new GE-Proton release and update the launch script |
|
||||
| `battlenet-diagnose.sh` | Check setup health and report anything broken |
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Enable `[multilib]` in `/etc/pacman.conf` if you haven't already. Uncomment these two lines:
|
||||
@@ -66,7 +103,17 @@ sudo pacman -S --needed \
|
||||
cups samba
|
||||
```
|
||||
|
||||
For an NVIDIA GPU, also install `lib32-nvidia-utils`. For AMD/Intel, `lib32-mesa` and `lib32-vulkan-radeon` or `lib32-vulkan-intel`.
|
||||
### GPU-specific packages
|
||||
|
||||
Install the right set for your GPU — getting this wrong is the most common reason a successful install fails to render:
|
||||
|
||||
| GPU | Extra packages to install |
|
||||
| ------------ | ---------------------------------------------------------------- |
|
||||
| **NVIDIA** | `lib32-nvidia-utils nvidia-utils` |
|
||||
| **AMD** | `lib32-mesa lib32-vulkan-radeon vulkan-radeon mesa` |
|
||||
| **Intel** | `lib32-mesa lib32-vulkan-intel vulkan-intel mesa` |
|
||||
|
||||
The `battlenet-umu-setup.sh` script auto-detects your GPU and installs the correct set. Override with `--gpu=nvidia|amd|intel` if detection is wrong.
|
||||
|
||||
---
|
||||
|
||||
@@ -85,13 +132,18 @@ For an NVIDIA GPU, also install `lib32-nvidia-utils`. For AMD/Intel, `lib32-mesa
|
||||
|
||||
[`umu-launcher`](https://github.com/Open-Wine-Components/umu-launcher) is the Open Wine Components project (from the GE-Proton maintainers) that makes Proton usable outside Steam. It manages Proton versions, runs games inside the Steam Runtime container, and automatically applies **protonfixes** — including the upstream fix for Battle.net that handles the `WINE_SIMULATE_WRITECOPY=1` workaround for you.
|
||||
|
||||
### 1. Install umu-launcher
|
||||
### 1. Install prerequisites and umu-launcher
|
||||
|
||||
Install the prerequisite packages from [Prerequisites](#prerequisites) above, then:
|
||||
|
||||
```bash
|
||||
sudo pacman -S umu-launcher
|
||||
```
|
||||
|
||||
Alternatively, `battlenet-umu-setup.sh` handles both in one step.
|
||||
|
||||
Verify:
|
||||
|
||||
```bash
|
||||
umu-run --help
|
||||
```
|
||||
@@ -114,6 +166,7 @@ umu-run ~/Downloads/Battle.net-Setup.exe
|
||||
```
|
||||
|
||||
umu will:
|
||||
|
||||
- Download the latest GE-Proton into `~/.local/share/Steam/compatibilitytools.d/` if it isn't there.
|
||||
- Create the prefix at `~/Games/battlenet-umu`.
|
||||
- Look up `umu-battlenet` in the protonfixes database and pre-apply the needed env vars and tweaks.
|
||||
@@ -123,6 +176,7 @@ Complete the installer at the default path.
|
||||
### 4. Create a launch script
|
||||
|
||||
`~/.local/bin/battlenet`:
|
||||
|
||||
```bash
|
||||
#!/bin/sh
|
||||
export WINEPREFIX="$HOME/Games/battlenet-umu"
|
||||
@@ -135,18 +189,20 @@ exec umu-run "$WINEPREFIX/drive_c/Program Files (x86)/Battle.net/Battle.net Laun
|
||||
chmod +x ~/.local/bin/battlenet
|
||||
```
|
||||
|
||||
Make sure `~/.local/bin` is on your `PATH` (it is by default on most Arch shells). Now `battlenet` in any terminal starts the launcher.
|
||||
Make sure `~/.local/bin` is on your `PATH`. See [Adding ~/.local/bin to PATH](#adding-localbin-to-path) below if it isn't. Once it is, `battlenet` in any terminal starts the launcher.
|
||||
|
||||
### 5. (Optional) Desktop entry
|
||||
|
||||
`~/.local/share/applications/battlenet.desktop`:
|
||||
|
||||
```ini
|
||||
[Desktop Entry]
|
||||
Name=Battle.net
|
||||
Exec=/home/YOUR_USERNAME/.local/bin/battlenet
|
||||
Exec=$HOME/.local/bin/battlenet
|
||||
Icon=battlenet
|
||||
Type=Application
|
||||
Categories=Game;
|
||||
StartupWMClass=battle.net.exe
|
||||
```
|
||||
|
||||
### 6. (Optional) Pin a specific Proton version
|
||||
@@ -157,7 +213,7 @@ If a GE-Proton release ever regresses Battle.net, pin a known-good one instead o
|
||||
export PROTONPATH="GE-Proton9-20"
|
||||
```
|
||||
|
||||
It needs to exist in `~/.local/share/Steam/compatibilitytools.d/`.
|
||||
It needs to exist in `~/.local/share/Steam/compatibilitytools.d/`. With the setup script, use `--proton-version=GE-Proton9-20`.
|
||||
|
||||
---
|
||||
|
||||
@@ -175,7 +231,7 @@ yay -S protonup-qt # or use paru, or grab the Flatpak
|
||||
|
||||
Log into Steam at least once. Open ProtonUp-Qt, point it at your Steam install, and install the latest **GE-Proton**. Restart Steam.
|
||||
|
||||
### 2. Download the Battle.net installer
|
||||
### 2. Get the Battle.net installer
|
||||
|
||||
Get `Battle.net-Setup.exe` from <https://download.battle.net/?product=bnetdesk>.
|
||||
|
||||
@@ -184,9 +240,11 @@ Get `Battle.net-Setup.exe` from <https://download.battle.net/?product=bnetdesk>.
|
||||
1. In Steam: **Games → Add a Non-Steam Game to My Library → Browse** and select `Battle.net-Setup.exe`.
|
||||
2. Right-click the new entry → **Properties → Compatibility** → tick **Force the use of a specific Steam Play compatibility tool** → select the latest **GE-Proton**.
|
||||
3. Under **Launch Options**, paste:
|
||||
```
|
||||
|
||||
```text
|
||||
WINE_SIMULATE_WRITECOPY=1 %command%
|
||||
```
|
||||
|
||||
This works around a CEF/login-screen issue that Blizzard periodically reintroduces with launcher updates. Cheap insurance.
|
||||
4. Launch it from Steam and complete the installer at the default path.
|
||||
|
||||
@@ -226,9 +284,9 @@ sudo pacman -S lutris
|
||||
|
||||
Right-click the Battle.net entry → **Configure → System options → Environment variables**:
|
||||
|
||||
| Key | Value |
|
||||
|---|---|
|
||||
| `WINE_SIMULATE_WRITECOPY` | `1` |
|
||||
| Key | Value |
|
||||
| -------------------------- | ----- |
|
||||
| `WINE_SIMULATE_WRITECOPY` | `1` |
|
||||
|
||||
---
|
||||
|
||||
@@ -288,6 +346,7 @@ WINE_SIMULATE_WRITECOPY=1 \
|
||||
### 4. Launch scripts
|
||||
|
||||
`~/.local/bin/battlenet`:
|
||||
|
||||
```bash
|
||||
#!/bin/sh
|
||||
export WINEPREFIX="$HOME/Games/battlenet-wine-prefix"
|
||||
@@ -296,6 +355,7 @@ exec wine "$WINEPREFIX/drive_c/Program Files (x86)/Battle.net/Battle.net Launche
|
||||
```
|
||||
|
||||
`~/.local/bin/battlenetkill`:
|
||||
|
||||
```bash
|
||||
#!/bin/sh
|
||||
export WINEPREFIX="$HOME/Games/battlenet-wine-prefix"
|
||||
@@ -308,6 +368,55 @@ chmod +x ~/.local/bin/battlenet ~/.local/bin/battlenetkill
|
||||
|
||||
---
|
||||
|
||||
## Adding ~/.local/bin to PATH
|
||||
|
||||
Most Arch shell setups include `~/.local/bin` automatically, but if yours doesn't:
|
||||
|
||||
**bash** — add to `~/.bashrc` or `~/.bash_profile`:
|
||||
|
||||
```bash
|
||||
export PATH="$HOME/.local/bin:$PATH"
|
||||
```
|
||||
|
||||
**zsh** — add to `~/.zshrc`:
|
||||
|
||||
```zsh
|
||||
export PATH="$HOME/.local/bin:$PATH"
|
||||
```
|
||||
|
||||
**fish** — run once; it persists across sessions:
|
||||
|
||||
```fish
|
||||
fish_add_path $HOME/.local/bin
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Game-specific notes
|
||||
|
||||
### World of Warcraft
|
||||
|
||||
Runs well out of the box on GE-Proton. A few tuning points:
|
||||
|
||||
- **D3D12 vs D3D11:** WoW defaults to D3D12 on recent clients. If you see crashes at launch, switch to D3D11 in the WoW graphics settings or add `PROTON_USE_WINED3D=0` and try D3D11 explicitly.
|
||||
- **High CPU usage at login screen:** Known issue with some GE-Proton builds. Pinning a slightly older release (e.g. `GE-Proton9-15`) often resolves it until the next fix lands.
|
||||
|
||||
### Overwatch 2
|
||||
|
||||
- Uses the **BattlEye** anti-cheat. BattlEye has official Linux support via the runtime bundled with Proton-GE; you do **not** need to disable it.
|
||||
- Add `PROTON_ENABLE_NVAPI=1` if you have NVIDIA and see the game refuse to launch with a GPU compatibility error.
|
||||
|
||||
### Diablo IV
|
||||
|
||||
- Runs well on GE-Proton. Uses **Warden** (no dedicated Linux anti-cheat binary) — no special config needed.
|
||||
- If you see corruption in cut-scenes, try `DXVK_ASYNC=1` in your launch script (async shader compilation).
|
||||
|
||||
### Hearthstone
|
||||
|
||||
Historically the most problematic title on Wine. With umu + protonfixes it works, but the login screen is particularly sensitive to `WINE_SIMULATE_WRITECOPY=1`. Make sure it's set (umu sets it automatically via protonfixes).
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Battle.net Update Agent went to sleep. Attempting to wake it up… BLZBNTBNA00000005"
|
||||
@@ -316,11 +425,13 @@ The most common 2025–2026 failure mode. In order:
|
||||
|
||||
1. Confirm `WINE_SIMULATE_WRITECOPY=1` is set (or that you're using umu/Lutris-via-umu, which sets it).
|
||||
2. Kill everything and wipe the agent cache:
|
||||
|
||||
```bash
|
||||
pkill -9 Battle.net; pkill -9 Agent; pkill -9 Blizzard
|
||||
rm -rf "$WINEPREFIX/drive_c/ProgramData/Battle.net/Agent"
|
||||
rm -rf "$WINEPREFIX/drive_c/ProgramData/Blizzard Entertainment"
|
||||
```
|
||||
|
||||
Restart the launcher; you'll have to log in again.
|
||||
3. Update GE-Proton. Fixes for Battle.net regressions usually land in a new GE-Proton release within days.
|
||||
|
||||
@@ -330,13 +441,33 @@ The most common 2025–2026 failure mode. In order:
|
||||
|
||||
### Blank window / broken input under Wayland
|
||||
|
||||
Wine's native Wayland driver is still rough for the Battle.net launcher in 2026. Either:
|
||||
- Log into an X11 session (SDDM/GDM login screen → session picker), or
|
||||
- Make sure you're going through XWayland — Steam/Proton does this automatically.
|
||||
Wine's native Wayland driver is still rough for the Battle.net launcher in 2026. The fix is to force XWayland explicitly:
|
||||
|
||||
```bash
|
||||
DISPLAY=:0 SDL_VIDEODRIVER=x11 battlenet
|
||||
```
|
||||
|
||||
Or add the overrides permanently to your launch script (`~/.local/bin/battlenet`):
|
||||
|
||||
```sh
|
||||
export DISPLAY="${DISPLAY:-:0}"
|
||||
export SDL_VIDEODRIVER=x11
|
||||
```
|
||||
|
||||
If `DISPLAY=:0` doesn't work, find the correct display number:
|
||||
|
||||
```bash
|
||||
ls /tmp/.X11-unix/
|
||||
```
|
||||
|
||||
Each `X<N>` file corresponds to `DISPLAY=:<N>`. Use whichever exists.
|
||||
|
||||
As a fallback, log into a plain **X11 session** from your display manager's session picker (SDDM/GDM). Steam/Proton routes through XWayland automatically, which is why Method 2 works without this tweak.
|
||||
|
||||
### "X Error of failed request: BadWindow" or X11 root-access errors
|
||||
|
||||
Caused by running Wine as root (what the old guide told you to do). **Don't.** If you're stuck with a root-owned prefix, remove it and start over as your normal user:
|
||||
|
||||
```bash
|
||||
sudo rm -rf /home/<user>/Games/battlenet-wine-prefix
|
||||
```
|
||||
@@ -344,12 +475,57 @@ sudo rm -rf /home/<user>/Games/battlenet-wine-prefix
|
||||
### Something else is broken
|
||||
|
||||
Delete the prefix and start over — this really does fix most weird states.
|
||||
|
||||
```bash
|
||||
rm -rf "$HOME/Games/battlenet-umu" # or battlenet-wine-prefix
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## systemd user service (optional)
|
||||
|
||||
If you want to start and stop Battle.net with `systemctl` rather than a terminal command, create a user service unit:
|
||||
|
||||
`~/.config/systemd/user/battlenet.service`:
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=Battle.net launcher (umu/Proton)
|
||||
After=graphical-session.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Environment=DISPLAY=:0
|
||||
ExecStart=%h/.local/bin/battlenet
|
||||
ExecStop=%h/.local/bin/battlenetkill
|
||||
Restart=no
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
```
|
||||
|
||||
Enable and control it:
|
||||
|
||||
```bash
|
||||
systemctl --user daemon-reload
|
||||
|
||||
# Start
|
||||
systemctl --user start battlenet
|
||||
|
||||
# Stop
|
||||
systemctl --user stop battlenet
|
||||
|
||||
# Start automatically at login
|
||||
systemctl --user enable battlenet
|
||||
|
||||
# View logs
|
||||
journalctl --user -u battlenet -f
|
||||
```
|
||||
|
||||
> **Note:** The `DISPLAY=:0` line assumes a single-user X11 or XWayland session. If your display number differs (check `ls /tmp/.X11-unix/`), update it. Under a proper XDG session you can also use `%I` socket activation, but for a game launcher `Type=simple` with a fixed display is simpler and more reliable.
|
||||
|
||||
---
|
||||
|
||||
## A note on bans
|
||||
|
||||
Blizzard does not ban for running via Wine/Proton/Linux. Their Warden anti-cheat targets cheat software inside the game process, not the compatibility layer. This has been confirmed by Blizzard support as recently as 2025.
|
||||
@@ -369,4 +545,13 @@ Blizzard does not ban for running via Wine/Proton/Linux. Their Warden anti-cheat
|
||||
- Added `WINE_SIMULATE_WRITECOPY=1` workaround for the modern CEF login/agent issues.
|
||||
- Replaced `/usr/bin/` install of user launch scripts with `~/.local/bin/`.
|
||||
- Set default Wine Windows version to Windows 10 rather than Windows 7.
|
||||
- Added Wayland/XWayland notes and the Agent-cache wipe fix for `BLZBNTBNA00000005`.
|
||||
- Added Wayland/XWayland notes and the Agent-cache wipe fix for `BLZBNTBNA00000005`.
|
||||
- Added GPU-specific package table to Prerequisites.
|
||||
- Added shell-specific PATH setup instructions (bash/zsh/fish).
|
||||
- Fixed desktop entry to use `$HOME` instead of hardcoded username.
|
||||
- Added game-specific notes for WoW, Overwatch 2, Diablo IV, and Hearthstone.
|
||||
- Added Quick start section with script flags and companion script table.
|
||||
- Added explicit XWayland fix (`DISPLAY=:0 SDL_VIDEODRIVER=x11`) to Wayland troubleshooting.
|
||||
- Added systemd user service unit for start/stop via `systemctl`.
|
||||
- Added `battlenet-update-proton.sh` — GE-Proton version manager.
|
||||
- Added `battlenet-diagnose.sh` — setup health checker.
|
||||
|
||||
Executable
+268
@@ -0,0 +1,268 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# battlenet-diagnose.sh
|
||||
#
|
||||
# Checks the health of your Battle.net / umu-launcher setup and reports
|
||||
# anything that looks wrong. Safe to run at any time — read-only, no changes.
|
||||
#
|
||||
# Usage:
|
||||
# ./battlenet-diagnose.sh
|
||||
# ./battlenet-diagnose.sh --prefix-dir=PATH # check a non-default prefix
|
||||
|
||||
set -uo pipefail
|
||||
|
||||
# ---------- config ----------
|
||||
PREFIX_DIR="${BATTLENET_PREFIX:-$HOME/Games/battlenet-umu}"
|
||||
LAUNCH_SCRIPT="${HOME}/.local/bin/battlenet"
|
||||
PROTON_COMPAT_DIR="${HOME}/.local/share/Steam/compatibilitytools.d"
|
||||
LAUNCHER_EXE_REL="drive_c/Program Files (x86)/Battle.net/Battle.net Launcher.exe"
|
||||
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--prefix-dir=*) PREFIX_DIR="${arg#*=}" ;;
|
||||
-h|--help) grep '^#' "$0" | grep -v '^#!/' | sed 's/^# \{0,1\}//'; exit 0 ;;
|
||||
*) echo "Unknown argument: $arg" >&2; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# ---------- helpers ----------
|
||||
c_reset=$'\033[0m'
|
||||
c_green=$'\033[1;32m'; c_yellow=$'\033[1;33m'; c_red=$'\033[1;31m'
|
||||
c_blue=$'\033[1;34m'; c_dim=$'\033[2m'; c_bold=$'\033[1m'
|
||||
|
||||
pass() { printf ' %s✓%s %s\n' "$c_green" "$c_reset" "$*"; }
|
||||
fail() { printf ' %s✗%s %s\n' "$c_red" "$c_reset" "$*"; ISSUES=$(( ISSUES + 1 )); }
|
||||
warn() { printf ' %s!%s %s\n' "$c_yellow" "$c_reset" "$*"; WARNINGS=$(( WARNINGS + 1 )); }
|
||||
info() { printf ' %s·%s %s\n' "$c_dim" "$c_reset" "$*"; }
|
||||
section() { printf '\n%s%s%s\n' "$c_bold$c_blue" "$*" "$c_reset"; }
|
||||
|
||||
ISSUES=0
|
||||
WARNINGS=0
|
||||
|
||||
# ---------- system ----------
|
||||
section "System"
|
||||
|
||||
info "Kernel: $(uname -r)"
|
||||
info "Date: $(date)"
|
||||
|
||||
if [[ $EUID -eq 0 ]]; then
|
||||
fail "Running as root — Wine/Proton must run as a regular user"
|
||||
else
|
||||
pass "Not running as root"
|
||||
fi
|
||||
|
||||
if pacman -Sl multilib >/dev/null 2>&1; then
|
||||
pass "[multilib] enabled"
|
||||
else
|
||||
fail "[multilib] not enabled — required for 32-bit libraries"
|
||||
fi
|
||||
|
||||
# ---------- GPU & drivers ----------
|
||||
section "GPU & Drivers"
|
||||
|
||||
GPU_LINE=""
|
||||
if command -v lspci >/dev/null 2>&1; then
|
||||
GPU_LINE=$(lspci | grep -i "VGA\|3D\|Display" | head -1 || true)
|
||||
if [[ -n "$GPU_LINE" ]]; then
|
||||
info "GPU: $GPU_LINE"
|
||||
else
|
||||
warn "No VGA/3D/Display device found via lspci"
|
||||
fi
|
||||
else
|
||||
warn "lspci not found (install pciutils) — GPU detection skipped"
|
||||
fi
|
||||
|
||||
# Vulkan
|
||||
if command -v vulkaninfo >/dev/null 2>&1; then
|
||||
if vulkaninfo 2>/dev/null | grep -q "apiVersion"; then
|
||||
VK_VER=$(vulkaninfo 2>/dev/null | grep "apiVersion" | head -1 | sed 's/.*= *//')
|
||||
pass "Vulkan available (apiVersion: $VK_VER)"
|
||||
else
|
||||
fail "vulkaninfo ran but reported no Vulkan devices"
|
||||
fi
|
||||
else
|
||||
warn "vulkaninfo not found — install vulkan-tools to verify Vulkan support"
|
||||
fi
|
||||
|
||||
# 32-bit Vulkan ICD loader
|
||||
if pacman -Qi lib32-vulkan-icd-loader >/dev/null 2>&1; then
|
||||
pass "lib32-vulkan-icd-loader installed"
|
||||
else
|
||||
fail "lib32-vulkan-icd-loader missing — install with: sudo pacman -S lib32-vulkan-icd-loader"
|
||||
fi
|
||||
|
||||
# ---------- umu-launcher ----------
|
||||
section "umu-launcher"
|
||||
|
||||
if command -v umu-run >/dev/null 2>&1; then
|
||||
UMU_PATH=$(command -v umu-run)
|
||||
UMU_VER=$(umu-run --version 2>/dev/null | head -1 || echo "unknown")
|
||||
pass "umu-run found: $UMU_PATH ($UMU_VER)"
|
||||
else
|
||||
fail "umu-run not on PATH — install with: sudo pacman -S umu-launcher"
|
||||
fi
|
||||
|
||||
# ---------- GE-Proton ----------
|
||||
section "GE-Proton"
|
||||
|
||||
if [[ -d "$PROTON_COMPAT_DIR" ]]; then
|
||||
mapfile -t PROTON_VERSIONS < <(find "$PROTON_COMPAT_DIR" -maxdepth 1 -type d -name "GE-Proton*" | sort -rV)
|
||||
if [[ ${#PROTON_VERSIONS[@]} -gt 0 ]]; then
|
||||
pass "${#PROTON_VERSIONS[@]} GE-Proton version(s) installed:"
|
||||
for v in "${PROTON_VERSIONS[@]}"; do
|
||||
info " $(basename "$v")"
|
||||
done
|
||||
else
|
||||
warn "No GE-Proton versions found in $PROTON_COMPAT_DIR"
|
||||
warn "umu-run will download GE-Proton automatically on first launch"
|
||||
fi
|
||||
else
|
||||
warn "Proton compat dir not found: $PROTON_COMPAT_DIR"
|
||||
warn "It will be created when umu-run downloads GE-Proton"
|
||||
fi
|
||||
|
||||
# Check what the launch script is pinned to
|
||||
if [[ -f "$LAUNCH_SCRIPT" ]]; then
|
||||
PINNED=$(grep '^export PROTONPATH=' "$LAUNCH_SCRIPT" 2>/dev/null | head -1 \
|
||||
| sed 's/.*="\?\([^"]*\)"\?.*/\1/' || echo "")
|
||||
if [[ -n "$PINNED" ]]; then
|
||||
info "Launch script pinned to: $PINNED"
|
||||
if [[ "$PINNED" == "GE-Proton" ]]; then
|
||||
info "(tracking latest — will auto-download if not present)"
|
||||
elif [[ -d "$PROTON_COMPAT_DIR/$PINNED" ]]; then
|
||||
pass "Pinned version is installed"
|
||||
else
|
||||
fail "Pinned version '$PINNED' not found in $PROTON_COMPAT_DIR"
|
||||
fail "Run: ./battlenet-update-proton.sh --version=$PINNED"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# ---------- prefix ----------
|
||||
section "Wine Prefix ($PREFIX_DIR)"
|
||||
|
||||
if [[ -d "$PREFIX_DIR" ]]; then
|
||||
pass "Prefix directory exists"
|
||||
|
||||
LAUNCHER_PATH="$PREFIX_DIR/$LAUNCHER_EXE_REL"
|
||||
if [[ -f "$LAUNCHER_PATH" ]]; then
|
||||
pass "Battle.net Launcher.exe present"
|
||||
else
|
||||
fail "Battle.net Launcher.exe NOT found at expected path"
|
||||
fail " Expected: $LAUNCHER_PATH"
|
||||
fail "Re-run battlenet-umu-setup.sh (or use --reinstall)"
|
||||
fi
|
||||
|
||||
# Check for common stuck-agent cache
|
||||
AGENT_LOCK="$PREFIX_DIR/drive_c/ProgramData/Battle.net/Agent/agent.lock"
|
||||
if [[ -f "$AGENT_LOCK" ]]; then
|
||||
LOCK_AGE=$(( $(date +%s) - $(stat -c%Y "$AGENT_LOCK") ))
|
||||
if (( LOCK_AGE > 300 )); then
|
||||
warn "Stale agent.lock found (${LOCK_AGE}s old) — may cause BLZBNTBNA00000005"
|
||||
warn "Fix: battlenetkill && rm -f \"$AGENT_LOCK\""
|
||||
else
|
||||
info "agent.lock exists but is fresh (${LOCK_AGE}s) — launcher may be running"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check prefix ownership
|
||||
if [[ -O "$PREFIX_DIR" ]]; then
|
||||
pass "Prefix is owned by current user"
|
||||
else
|
||||
fail "Prefix is NOT owned by current user — Wine will misbehave"
|
||||
fail "Fix: sudo chown -R $(whoami): \"$PREFIX_DIR\""
|
||||
fi
|
||||
else
|
||||
fail "Prefix directory does not exist: $PREFIX_DIR"
|
||||
fail "Run battlenet-umu-setup.sh to create it"
|
||||
fi
|
||||
|
||||
# ---------- launch scripts ----------
|
||||
section "Launch Scripts"
|
||||
|
||||
if [[ -f "$LAUNCH_SCRIPT" ]]; then
|
||||
pass "Launch script exists: $LAUNCH_SCRIPT"
|
||||
if [[ -x "$LAUNCH_SCRIPT" ]]; then
|
||||
pass "Launch script is executable"
|
||||
else
|
||||
fail "Launch script is NOT executable — run: chmod +x $LAUNCH_SCRIPT"
|
||||
fi
|
||||
|
||||
# Verify env vars are present
|
||||
for var in WINEPREFIX GAMEID PROTONPATH; do
|
||||
if grep -q "^export $var=" "$LAUNCH_SCRIPT"; then
|
||||
VAL=$(grep "^export $var=" "$LAUNCH_SCRIPT" | head -1 | sed 's/.*="\?\([^"]*\)"\?.*/\1/')
|
||||
info "$var=$VAL"
|
||||
else
|
||||
fail "Launch script missing: export $var=..."
|
||||
fi
|
||||
done
|
||||
else
|
||||
fail "Launch script not found: $LAUNCH_SCRIPT"
|
||||
fail "Run battlenet-umu-setup.sh to create it"
|
||||
fi
|
||||
|
||||
KILL_SCRIPT="$HOME/.local/bin/battlenetkill"
|
||||
if [[ -f "$KILL_SCRIPT" && -x "$KILL_SCRIPT" ]]; then
|
||||
pass "Kill script exists and is executable: $KILL_SCRIPT"
|
||||
else
|
||||
warn "Kill script missing or not executable: $KILL_SCRIPT"
|
||||
fi
|
||||
|
||||
# ---------- display / Wayland ----------
|
||||
section "Display"
|
||||
|
||||
if [[ -n "${WAYLAND_DISPLAY:-}" ]]; then
|
||||
info "Wayland session detected (WAYLAND_DISPLAY=$WAYLAND_DISPLAY)"
|
||||
if [[ -n "${DISPLAY:-}" ]]; then
|
||||
pass "XWayland is available (DISPLAY=$DISPLAY)"
|
||||
info "Battle.net will run via XWayland — this is correct"
|
||||
else
|
||||
fail "No DISPLAY set — XWayland does not appear to be running"
|
||||
fail "Battle.net requires XWayland under Wayland"
|
||||
fail "Make sure your compositor starts XWayland (most do by default)"
|
||||
fi
|
||||
elif [[ -n "${DISPLAY:-}" ]]; then
|
||||
pass "X11 session (DISPLAY=$DISPLAY)"
|
||||
else
|
||||
warn "Neither DISPLAY nor WAYLAND_DISPLAY is set — running headless?"
|
||||
fi
|
||||
|
||||
# ---------- running processes ----------
|
||||
section "Running Processes"
|
||||
|
||||
BN_PROCS=$(pgrep -fl 'Battle\.net\|battle\.net\|bnet' 2>/dev/null || true)
|
||||
AGENT_PROCS=$(pgrep -fl 'Agent\.exe' 2>/dev/null || true)
|
||||
WINE_PROCS=$(pgrep -fl 'wine\|wineserver\|proton' 2>/dev/null | grep -v 'grep' || true)
|
||||
|
||||
if [[ -n "$BN_PROCS" ]]; then
|
||||
info "Battle.net process(es) running:"
|
||||
while IFS= read -r line; do info " $line"; done <<< "$BN_PROCS"
|
||||
else
|
||||
info "No Battle.net processes running"
|
||||
fi
|
||||
|
||||
if [[ -n "$AGENT_PROCS" ]]; then
|
||||
info "Agent process(es) running:"
|
||||
while IFS= read -r line; do info " $line"; done <<< "$AGENT_PROCS"
|
||||
fi
|
||||
|
||||
if [[ -n "$WINE_PROCS" ]]; then
|
||||
info "Wine/Proton process(es) running:"
|
||||
while IFS= read -r line; do info " $line"; done <<< "$WINE_PROCS"
|
||||
fi
|
||||
|
||||
# ---------- summary ----------
|
||||
echo
|
||||
printf '%s%s%s\n' "$c_bold$c_blue" "=== Summary ===" "$c_reset"
|
||||
|
||||
if [[ $ISSUES -eq 0 && $WARNINGS -eq 0 ]]; then
|
||||
printf '%s✓ Everything looks good.%s\n' "$c_green" "$c_reset"
|
||||
elif [[ $ISSUES -eq 0 ]]; then
|
||||
printf '%s! %d warning(s). Battle.net should work, but check the items above.%s\n' \
|
||||
"$c_yellow" "$WARNINGS" "$c_reset"
|
||||
else
|
||||
printf '%s✗ %d issue(s), %d warning(s). See items marked ✗ above.%s\n' \
|
||||
"$c_red" "$ISSUES" "$WARNINGS" "$c_reset"
|
||||
fi
|
||||
echo
|
||||
+237
-37
@@ -6,9 +6,14 @@
|
||||
# Idempotent: safe to re-run. Skips steps that are already done.
|
||||
#
|
||||
# Usage:
|
||||
# ./battlenet-umu-setup.sh # interactive
|
||||
# ./battlenet-umu-setup.sh --yes # non-interactive, assume yes
|
||||
# ./battlenet-umu-setup.sh --reinstall # wipe prefix and reinstall
|
||||
# ./battlenet-umu-setup.sh # interactive
|
||||
# ./battlenet-umu-setup.sh --yes # non-interactive, assume yes
|
||||
# ./battlenet-umu-setup.sh --reinstall # wipe prefix and reinstall
|
||||
# ./battlenet-umu-setup.sh --proton-version=GE-Proton9-20 # pin a specific Proton version
|
||||
# ./battlenet-umu-setup.sh --gpu=nvidia|amd|intel # override GPU detection
|
||||
# ./battlenet-umu-setup.sh --prefix-dir=PATH # override prefix location
|
||||
# ./battlenet-umu-setup.sh --skip-packages # skip prerequisite package check
|
||||
# END_HELP
|
||||
#
|
||||
# Does NOT run itself as root. It will call sudo only for pacman.
|
||||
|
||||
@@ -17,27 +22,33 @@ set -euo pipefail
|
||||
# ---------- config ----------
|
||||
PREFIX_DIR="${BATTLENET_PREFIX:-$HOME/Games/battlenet-umu}"
|
||||
GAMEID="umu-battlenet"
|
||||
PROTONPATH="${PROTONPATH:-GE-Proton}"
|
||||
PROTON_VERSION="GE-Proton" # default; overridden by --proton-version or PROTONPATH env var
|
||||
INSTALLER_URL="https://downloader.battle.net/download/getInstaller?os=win&installer=Battle.net-Setup.exe"
|
||||
INSTALLER_PATH="$HOME/Downloads/Battle.net-Setup.exe"
|
||||
LAUNCHER_EXE_REL="drive_c/Program Files (x86)/Battle.net/Battle.net Launcher.exe"
|
||||
BIN_DIR="$HOME/.local/bin"
|
||||
DESKTOP_DIR="$HOME/.local/share/applications"
|
||||
ICON_DIR="$HOME/.local/share/icons/hicolor/256x256/apps"
|
||||
LAUNCH_SCRIPT="$BIN_DIR/battlenet"
|
||||
KILL_SCRIPT="$BIN_DIR/battlenetkill"
|
||||
DESKTOP_FILE="$DESKTOP_DIR/battlenet.desktop"
|
||||
|
||||
ASSUME_YES=0
|
||||
REINSTALL=0
|
||||
SKIP_PACKAGES=0
|
||||
GPU_TYPE="" # auto-detected; override with --gpu=nvidia|amd|intel
|
||||
|
||||
# Honour PROTONPATH env var as a default, but let --proton-version override it
|
||||
[[ -n "${PROTONPATH:-}" ]] && PROTON_VERSION="$PROTONPATH"
|
||||
|
||||
# ---------- helpers ----------
|
||||
c_reset=$'\033[0m'; c_blue=$'\033[1;34m'; c_green=$'\033[1;32m'
|
||||
c_yellow=$'\033[1;33m'; c_red=$'\033[1;31m'; c_dim=$'\033[2m'
|
||||
|
||||
log() { printf '%s==>%s %s\n' "$c_blue" "$c_reset" "$*"; }
|
||||
ok() { printf '%s✓%s %s\n' "$c_green" "$c_reset" "$*"; }
|
||||
log() { printf '%s==>%s %s\n' "$c_blue" "$c_reset" "$*"; }
|
||||
ok() { printf '%s✓%s %s\n' "$c_green" "$c_reset" "$*"; }
|
||||
warn() { printf '%s!%s %s\n' "$c_yellow" "$c_reset" "$*"; }
|
||||
err() { printf '%s✗%s %s\n' "$c_red" "$c_reset" "$*" >&2; }
|
||||
err() { printf '%s✗%s %s\n' "$c_red" "$c_reset" "$*" >&2; }
|
||||
skip() { printf ' %s(skip) %s%s\n' "$c_dim" "$*" "$c_reset"; }
|
||||
|
||||
confirm() {
|
||||
@@ -54,23 +65,32 @@ die() { err "$*"; exit 1; }
|
||||
# ---------- arg parsing ----------
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
-y|--yes) ASSUME_YES=1 ;;
|
||||
--reinstall) REINSTALL=1 ;;
|
||||
-y|--yes) ASSUME_YES=1 ;;
|
||||
--reinstall) REINSTALL=1 ;;
|
||||
--skip-packages) SKIP_PACKAGES=1 ;;
|
||||
--proton-version=*) PROTON_VERSION="${arg#*=}" ;;
|
||||
--prefix-dir=*) PREFIX_DIR="${arg#*=}" ;;
|
||||
--gpu=nvidia|--gpu=amd|--gpu=intel)
|
||||
GPU_TYPE="${arg#*=}" ;;
|
||||
-h|--help)
|
||||
sed -n '2,12p' "$0" | sed 's/^# \{0,1\}//'
|
||||
sed -n '/^# Usage:/,/^# END_HELP/p' "$0" | sed 's/^# \{0,1\}//'
|
||||
exit 0
|
||||
;;
|
||||
*) die "Unknown argument: $arg" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Expose PROTONPATH for umu-run
|
||||
PROTONPATH="$PROTON_VERSION"
|
||||
export PROTONPATH
|
||||
|
||||
# ---------- preflight ----------
|
||||
log "Preflight checks"
|
||||
|
||||
[[ $EUID -ne 0 ]] || die "Do not run this script as root. It will sudo when it needs to."
|
||||
|
||||
command -v pacman >/dev/null || die "pacman not found — this script is for Arch Linux."
|
||||
command -v curl >/dev/null || die "curl not installed. sudo pacman -S curl"
|
||||
command -v curl >/dev/null || die "curl not installed. Run: sudo pacman -S curl"
|
||||
|
||||
# multilib check
|
||||
if ! pacman -Sl multilib >/dev/null 2>&1; then
|
||||
@@ -81,6 +101,81 @@ if ! pacman -Sl multilib >/dev/null 2>&1; then
|
||||
fi
|
||||
ok "[multilib] is enabled"
|
||||
|
||||
# ---------- detect GPU ----------
|
||||
log "Detecting GPU"
|
||||
|
||||
if [[ -z "$GPU_TYPE" ]]; then
|
||||
if command -v lspci >/dev/null 2>&1; then
|
||||
if lspci | grep -qi "NVIDIA"; then
|
||||
GPU_TYPE="nvidia"
|
||||
elif lspci | grep -qi "AMD\|Radeon"; then
|
||||
GPU_TYPE="amd"
|
||||
else
|
||||
GPU_TYPE="intel"
|
||||
fi
|
||||
else
|
||||
warn "lspci not found (install pciutils for auto-detection). Defaulting to intel."
|
||||
warn "Override with --gpu=nvidia|amd|intel if that is wrong."
|
||||
GPU_TYPE="intel"
|
||||
fi
|
||||
fi
|
||||
ok "GPU type: $GPU_TYPE (override with --gpu=nvidia|amd|intel)"
|
||||
|
||||
# ---------- install prerequisites ----------
|
||||
if [[ $SKIP_PACKAGES -eq 1 ]]; then
|
||||
skip "Package check skipped (--skip-packages)"
|
||||
else
|
||||
log "Checking 32-bit prerequisite libraries"
|
||||
|
||||
COMMON_PKGS=(
|
||||
giflib lib32-giflib
|
||||
libpng lib32-libpng
|
||||
libldap lib32-libldap
|
||||
gnutls lib32-gnutls
|
||||
mpg123 lib32-mpg123
|
||||
openal lib32-openal
|
||||
v4l-utils lib32-v4l-utils
|
||||
libpulse lib32-libpulse
|
||||
alsa-plugins lib32-alsa-plugins
|
||||
alsa-lib lib32-alsa-lib
|
||||
libjpeg-turbo lib32-libjpeg-turbo
|
||||
sqlite lib32-sqlite
|
||||
libxcomposite lib32-libxcomposite
|
||||
libxinerama lib32-libxinerama
|
||||
ncurses lib32-ncurses
|
||||
opencl-icd-loader lib32-opencl-icd-loader
|
||||
libxslt lib32-libxslt
|
||||
libva lib32-libva
|
||||
gtk3 lib32-gtk3
|
||||
gst-plugins-base-libs lib32-gst-plugins-base-libs
|
||||
vulkan-icd-loader lib32-vulkan-icd-loader
|
||||
cups samba
|
||||
)
|
||||
|
||||
GPU_PKGS=()
|
||||
case "$GPU_TYPE" in
|
||||
nvidia) GPU_PKGS=(lib32-nvidia-utils nvidia-utils) ;;
|
||||
amd) GPU_PKGS=(lib32-mesa lib32-vulkan-radeon vulkan-radeon mesa) ;;
|
||||
intel) GPU_PKGS=(lib32-mesa lib32-vulkan-intel vulkan-intel mesa) ;;
|
||||
esac
|
||||
|
||||
ALL_PKGS=("${COMMON_PKGS[@]}" "${GPU_PKGS[@]}")
|
||||
|
||||
MISSING_PKGS=()
|
||||
for pkg in "${ALL_PKGS[@]}"; do
|
||||
pacman -Qi "$pkg" >/dev/null 2>&1 || MISSING_PKGS+=("$pkg")
|
||||
done
|
||||
|
||||
if [[ ${#MISSING_PKGS[@]} -eq 0 ]]; then
|
||||
skip "All prerequisite packages already installed"
|
||||
else
|
||||
warn "Missing packages: ${MISSING_PKGS[*]}"
|
||||
confirm "Install missing prerequisite packages?" || die "Aborted."
|
||||
sudo pacman -S --needed --noconfirm "${MISSING_PKGS[@]}"
|
||||
ok "Prerequisite packages installed"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ---------- install umu-launcher ----------
|
||||
log "Installing umu-launcher"
|
||||
|
||||
@@ -98,14 +193,34 @@ command -v umu-run >/dev/null || die "umu-run not on PATH after install — some
|
||||
log "Fetching Battle.net installer"
|
||||
|
||||
mkdir -p "$(dirname "$INSTALLER_PATH")"
|
||||
|
||||
_download_installer() {
|
||||
curl -L --fail --progress-bar -o "$INSTALLER_PATH" "$INSTALLER_URL"
|
||||
# Sanity check: Battle.net-Setup.exe is always several MB; <100 KB means a redirect page or error.
|
||||
local size
|
||||
size=$(stat -c%s "$INSTALLER_PATH" 2>/dev/null || echo 0)
|
||||
if (( size < 102400 )); then
|
||||
rm -f "$INSTALLER_PATH"
|
||||
die "Downloaded file is suspiciously small (${size} bytes) — download may have failed."
|
||||
fi
|
||||
}
|
||||
|
||||
if [[ -f "$INSTALLER_PATH" ]]; then
|
||||
skip "Installer already at $INSTALLER_PATH"
|
||||
if confirm "Re-download to get the latest?"; then
|
||||
curl -L --fail -o "$INSTALLER_PATH" "$INSTALLER_URL"
|
||||
ok "Installer re-downloaded"
|
||||
local_size=$(stat -c%s "$INSTALLER_PATH" 2>/dev/null || echo 0)
|
||||
if (( local_size < 102400 )); then
|
||||
warn "Existing installer looks corrupt (${local_size} bytes). Re-downloading."
|
||||
_download_installer
|
||||
ok "Installer downloaded to $INSTALLER_PATH"
|
||||
else
|
||||
skip "Installer already at $INSTALLER_PATH ($(( local_size / 1024 / 1024 )) MB)"
|
||||
# When running non-interactively (--yes), keep the existing file; only re-download on explicit prompt.
|
||||
if [[ $ASSUME_YES -eq 0 ]] && confirm "Re-download to get the latest?"; then
|
||||
_download_installer
|
||||
ok "Installer re-downloaded"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
curl -L --fail -o "$INSTALLER_PATH" "$INSTALLER_URL"
|
||||
_download_installer
|
||||
ok "Installer saved to $INSTALLER_PATH"
|
||||
fi
|
||||
|
||||
@@ -146,9 +261,13 @@ else
|
||||
warn "umu-run exited non-zero. That's often normal for the Battle.net installer."
|
||||
}
|
||||
|
||||
# The installer sometimes drops the launcher even if it exits weirdly.
|
||||
# Give it a moment, then check.
|
||||
sleep 2
|
||||
# The installer sometimes exits before the launcher EXE is flushed to disk.
|
||||
# Poll for up to 30 s rather than assuming a fixed delay is enough.
|
||||
i=0
|
||||
while [[ ! -f "$LAUNCHER_PATH" && $i -lt 30 ]]; do
|
||||
sleep 1
|
||||
(( i++ )) || true
|
||||
done
|
||||
|
||||
if [[ ! -f "$LAUNCHER_PATH" ]]; then
|
||||
err "Battle.net Launcher.exe not found at expected path:"
|
||||
@@ -159,6 +278,52 @@ else
|
||||
ok "Battle.net installed into prefix"
|
||||
fi
|
||||
|
||||
# ---------- icon ----------
|
||||
log "Installing icon"
|
||||
|
||||
ICON_SRC="$PREFIX_DIR/drive_c/Program Files (x86)/Battle.net/Battle.net Launcher.exe"
|
||||
ICON_PNG="$ICON_DIR/battlenet.png"
|
||||
|
||||
_install_icon() {
|
||||
local tmpdir
|
||||
tmpdir=$(mktemp -d)
|
||||
trap 'rm -rf "$tmpdir"' RETURN
|
||||
|
||||
# Extract the largest icon group from the EXE, then convert to PNG.
|
||||
# wrestool and icotool come from the 'icoutils' package.
|
||||
if command -v wrestool >/dev/null && command -v icotool >/dev/null; then
|
||||
if wrestool -x -t 14 "$ICON_SRC" -o "$tmpdir" 2>/dev/null; then
|
||||
local ico
|
||||
ico=$(find "$tmpdir" -name "*.ico" | head -1)
|
||||
if [[ -n "$ico" ]]; then
|
||||
mkdir -p "$ICON_DIR"
|
||||
icotool -x --index=1 -o "$ICON_DIR" "$ico" 2>/dev/null \
|
||||
&& mv "$ICON_DIR/"*_1_*.png "$ICON_PNG" 2>/dev/null \
|
||||
&& ok "Icon installed to $ICON_PNG" \
|
||||
&& return 0
|
||||
fi
|
||||
fi
|
||||
warn "Icon extraction failed — Battle.net may not be installed yet, or the EXE layout changed."
|
||||
else
|
||||
warn "icoutils (wrestool/icotool) not installed. Skipping icon extraction."
|
||||
warn "Install with: sudo pacman -S icoutils"
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
if [[ -f "$ICON_PNG" ]]; then
|
||||
skip "Icon already at $ICON_PNG"
|
||||
elif [[ -f "$ICON_SRC" ]]; then
|
||||
_install_icon || true
|
||||
else
|
||||
skip "Launcher EXE not found; skipping icon (will retry on next run)"
|
||||
fi
|
||||
|
||||
# Refresh icon cache best-effort
|
||||
if command -v gtk-update-icon-cache >/dev/null; then
|
||||
gtk-update-icon-cache -f -t "$HOME/.local/share/icons/hicolor" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# ---------- launch scripts ----------
|
||||
log "Installing launch scripts to $BIN_DIR"
|
||||
|
||||
@@ -167,54 +332,88 @@ mkdir -p "$BIN_DIR"
|
||||
cat > "$LAUNCH_SCRIPT" <<EOF
|
||||
#!/bin/sh
|
||||
# Auto-generated by battlenet-umu-setup.sh
|
||||
# Proton version: $PROTON_VERSION
|
||||
export WINEPREFIX="$PREFIX_DIR"
|
||||
export GAMEID="$GAMEID"
|
||||
export PROTONPATH="$PROTONPATH"
|
||||
export PROTONPATH="$PROTON_VERSION"
|
||||
exec umu-run "\$WINEPREFIX/$LAUNCHER_EXE_REL" "\$@"
|
||||
EOF
|
||||
chmod +x "$LAUNCH_SCRIPT"
|
||||
ok "Wrote $LAUNCH_SCRIPT"
|
||||
|
||||
cat > "$KILL_SCRIPT" <<EOF
|
||||
cat > "$KILL_SCRIPT" <<'KILL_EOF'
|
||||
#!/bin/sh
|
||||
# Auto-generated by battlenet-umu-setup.sh
|
||||
# Kills the Battle.net launcher and all Wine/Proton processes for this prefix.
|
||||
export WINEPREFIX="$PREFIX_DIR"
|
||||
pkill -9 -f 'Battle\\.net' 2>/dev/null || true
|
||||
pkill -9 -f 'Agent\\.exe' 2>/dev/null || true
|
||||
pkill -9 -f 'Blizzard' 2>/dev/null || true
|
||||
# Gracefully stops Battle.net, then force-kills after a timeout.
|
||||
|
||||
_graceful_kill() {
|
||||
local pattern="$1"
|
||||
# Try SIGTERM first
|
||||
pkill -15 -f "$pattern" 2>/dev/null || return 0
|
||||
local i=0
|
||||
while pkill -0 -f "$pattern" 2>/dev/null && [ $i -lt 5 ]; do
|
||||
sleep 1
|
||||
i=$(( i + 1 ))
|
||||
done
|
||||
# Force-kill anything still alive
|
||||
pkill -9 -f "$pattern" 2>/dev/null || true
|
||||
}
|
||||
|
||||
_graceful_kill 'Battle\.net'
|
||||
_graceful_kill 'Agent\.exe'
|
||||
_graceful_kill 'Blizzard'
|
||||
|
||||
# wineserver may not be on PATH in umu environments; try both.
|
||||
if command -v wineserver >/dev/null; then
|
||||
wineserver -k 2>/dev/null || true
|
||||
fi
|
||||
EOF
|
||||
KILL_EOF
|
||||
chmod +x "$KILL_SCRIPT"
|
||||
ok "Wrote $KILL_SCRIPT"
|
||||
|
||||
# PATH check
|
||||
# PATH check — show shell-appropriate instructions
|
||||
case ":$PATH:" in
|
||||
*":$BIN_DIR:"*) ok "$BIN_DIR is on PATH" ;;
|
||||
*) warn "$BIN_DIR is not on your PATH. Add this to your shell rc:"
|
||||
warn " export PATH=\"\$HOME/.local/bin:\$PATH\"" ;;
|
||||
*)
|
||||
warn "$BIN_DIR is not on your PATH."
|
||||
_shell_name="$(basename "${SHELL:-bash}")"
|
||||
case "$_shell_name" in
|
||||
fish)
|
||||
warn "Add it permanently with:"
|
||||
warn " fish_add_path \$HOME/.local/bin"
|
||||
;;
|
||||
zsh)
|
||||
warn "Add this to ~/.zshrc:"
|
||||
warn " export PATH=\"\$HOME/.local/bin:\$PATH\""
|
||||
;;
|
||||
*)
|
||||
warn "Add this to ~/.bashrc (or ~/.profile for login shells):"
|
||||
warn " export PATH=\"\$HOME/.local/bin:\$PATH\""
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
|
||||
# ---------- desktop entry ----------
|
||||
log "Installing desktop entry"
|
||||
|
||||
# Use extracted icon if available, fall back to generic game icon
|
||||
ICON_NAME="battlenet"
|
||||
[[ -f "$ICON_PNG" ]] || ICON_NAME="applications-games"
|
||||
|
||||
mkdir -p "$DESKTOP_DIR"
|
||||
cat > "$DESKTOP_FILE" <<EOF
|
||||
[Desktop Entry]
|
||||
Name=Battle.net
|
||||
Comment=Blizzard launcher (umu/Proton)
|
||||
Exec=$LAUNCH_SCRIPT
|
||||
Icon=battlenet
|
||||
Icon=$ICON_NAME
|
||||
Type=Application
|
||||
Categories=Game;
|
||||
StartupWMClass=battle.net.exe
|
||||
EOF
|
||||
ok "Wrote $DESKTOP_FILE"
|
||||
|
||||
# Refresh the desktop database if the tool is around — best-effort only.
|
||||
if command -v update-desktop-database >/dev/null; then
|
||||
update-desktop-database "$DESKTOP_DIR" 2>/dev/null || true
|
||||
fi
|
||||
@@ -223,10 +422,11 @@ fi
|
||||
echo
|
||||
ok "Setup complete."
|
||||
echo
|
||||
echo " Prefix: $PREFIX_DIR"
|
||||
echo " Launcher: $LAUNCH_SCRIPT"
|
||||
echo " Kill: $KILL_SCRIPT"
|
||||
echo " Desktop: $DESKTOP_FILE"
|
||||
echo " Prefix: $PREFIX_DIR"
|
||||
echo " Proton: $PROTON_VERSION"
|
||||
echo " Launcher: $LAUNCH_SCRIPT"
|
||||
echo " Kill: $KILL_SCRIPT"
|
||||
echo " Desktop: $DESKTOP_FILE"
|
||||
echo
|
||||
echo "Run 'battlenet' to start it, or launch from your app menu."
|
||||
echo "If it hangs on 'Update Agent went to sleep', run: battlenetkill && battlenet"
|
||||
echo "If it hangs on 'Update Agent went to sleep', run: battlenetkill && battlenet"
|
||||
|
||||
Executable
+166
@@ -0,0 +1,166 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# battlenet-update-proton.sh
|
||||
#
|
||||
# Lists available GE-Proton releases from GitHub, downloads the chosen version
|
||||
# into ~/.local/share/Steam/compatibilitytools.d/, and updates the battlenet
|
||||
# launch script to point at it.
|
||||
#
|
||||
# Usage:
|
||||
# ./battlenet-update-proton.sh # interactive picker
|
||||
# ./battlenet-update-proton.sh --latest # auto-install the latest release
|
||||
# ./battlenet-update-proton.sh --list # list available releases and exit
|
||||
# ./battlenet-update-proton.sh --version=GE-Proton9-20 # install a specific release
|
||||
# END_HELP
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# ---------- config ----------
|
||||
PROTON_DIR="${PROTON_INSTALL_DIR:-$HOME/.local/share/Steam/compatibilitytools.d}"
|
||||
LAUNCH_SCRIPT="${BATTLENET_LAUNCH_SCRIPT:-$HOME/.local/bin/battlenet}"
|
||||
GITHUB_API="https://api.github.com/repos/GloriousEggroll/proton-ge-custom/releases"
|
||||
LIST_COUNT=10 # how many recent releases to show in the picker
|
||||
|
||||
ASSUME_LATEST=0
|
||||
LIST_ONLY=0
|
||||
PINNED_VERSION=""
|
||||
|
||||
# ---------- helpers ----------
|
||||
c_reset=$'\033[0m'; c_blue=$'\033[1;34m'; c_green=$'\033[1;32m'
|
||||
c_yellow=$'\033[1;33m'; c_red=$'\033[1;31m'; c_dim=$'\033[2m'
|
||||
|
||||
log() { printf '%s==>%s %s\n' "$c_blue" "$c_reset" "$*"; }
|
||||
ok() { printf '%s✓%s %s\n' "$c_green" "$c_reset" "$*"; }
|
||||
warn() { printf '%s!%s %s\n' "$c_yellow" "$c_reset" "$*"; }
|
||||
err() { printf '%s✗%s %s\n' "$c_red" "$c_reset" "$*" >&2; }
|
||||
skip() { printf ' %s(skip) %s%s\n' "$c_dim" "$*" "$c_reset"; }
|
||||
die() { err "$*"; exit 1; }
|
||||
|
||||
# ---------- arg parsing ----------
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--latest) ASSUME_LATEST=1 ;;
|
||||
--list) LIST_ONLY=1 ;;
|
||||
--version=*) PINNED_VERSION="${arg#*=}" ;;
|
||||
-h|--help)
|
||||
sed -n '/^# Usage:/,/^# END_HELP/p' "$0" | sed 's/^# \{0,1\}//'
|
||||
exit 0
|
||||
;;
|
||||
*) die "Unknown argument: $arg" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# ---------- preflight ----------
|
||||
command -v curl >/dev/null || die "curl not installed. Run: sudo pacman -S curl"
|
||||
command -v tar >/dev/null || die "tar not installed."
|
||||
|
||||
# ---------- fetch release list ----------
|
||||
log "Fetching GE-Proton release list from GitHub"
|
||||
|
||||
RELEASES_JSON=$(curl -fsSL "$GITHUB_API?per_page=$LIST_COUNT")
|
||||
|
||||
# Extract tag names (GE-ProtonX-Y format)
|
||||
mapfile -t RELEASE_TAGS < <(
|
||||
printf '%s' "$RELEASES_JSON" \
|
||||
| grep '"tag_name"' \
|
||||
| sed 's/.*"tag_name": *"\([^"]*\)".*/\1/'
|
||||
)
|
||||
|
||||
[[ ${#RELEASE_TAGS[@]} -gt 0 ]] || die "No releases found — GitHub API may be rate-limited. Try again shortly."
|
||||
|
||||
if [[ $LIST_ONLY -eq 1 ]]; then
|
||||
echo "Recent GE-Proton releases:"
|
||||
for tag in "${RELEASE_TAGS[@]}"; do
|
||||
installed=""
|
||||
[[ -d "$PROTON_DIR/$tag" ]] && installed=" ${c_green}(installed)${c_reset}"
|
||||
printf " %s%s\n" "$tag" "$installed"
|
||||
done
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# ---------- choose version ----------
|
||||
if [[ -n "$PINNED_VERSION" ]]; then
|
||||
TARGET="$PINNED_VERSION"
|
||||
elif [[ $ASSUME_LATEST -eq 1 ]]; then
|
||||
TARGET="${RELEASE_TAGS[0]}"
|
||||
log "Latest release: $TARGET"
|
||||
else
|
||||
echo
|
||||
echo "Recent GE-Proton releases (${c_green}green = already installed${c_reset}):"
|
||||
i=1
|
||||
for tag in "${RELEASE_TAGS[@]}"; do
|
||||
installed=""
|
||||
[[ -d "$PROTON_DIR/$tag" ]] && installed=" ${c_green}✓${c_reset}"
|
||||
printf " %2d) %s%s\n" "$i" "$tag" "$installed"
|
||||
(( i++ ))
|
||||
done
|
||||
echo
|
||||
printf "Enter number (1-%d) or a version tag [default: 1 = %s]: " "${#RELEASE_TAGS[@]}" "${RELEASE_TAGS[0]}"
|
||||
read -r choice
|
||||
if [[ -z "$choice" ]]; then
|
||||
TARGET="${RELEASE_TAGS[0]}"
|
||||
elif [[ "$choice" =~ ^[0-9]+$ ]] && (( choice >= 1 && choice <= ${#RELEASE_TAGS[@]} )); then
|
||||
TARGET="${RELEASE_TAGS[$(( choice - 1 ))]}"
|
||||
else
|
||||
TARGET="$choice"
|
||||
fi
|
||||
fi
|
||||
|
||||
log "Target: $TARGET"
|
||||
|
||||
# ---------- download ----------
|
||||
INSTALL_PATH="$PROTON_DIR/$TARGET"
|
||||
|
||||
if [[ -d "$INSTALL_PATH" ]]; then
|
||||
skip "$TARGET already installed at $INSTALL_PATH"
|
||||
else
|
||||
# Find the .tar.gz asset URL for this release
|
||||
log "Resolving download URL for $TARGET"
|
||||
ASSET_URL=$(
|
||||
curl -fsSL "$GITHUB_API/tags/$TARGET" \
|
||||
| grep '"browser_download_url"' \
|
||||
| grep '\.tar\.gz"' \
|
||||
| head -1 \
|
||||
| sed 's/.*"browser_download_url": *"\([^"]*\)".*/\1/'
|
||||
)
|
||||
[[ -n "$ASSET_URL" ]] || die "Could not find a .tar.gz asset for $TARGET. Check the version name."
|
||||
|
||||
log "Downloading $TARGET"
|
||||
TMPFILE=$(mktemp --suffix=.tar.gz)
|
||||
trap 'rm -f "$TMPFILE"' EXIT
|
||||
|
||||
curl -L --fail --progress-bar -o "$TMPFILE" "$ASSET_URL"
|
||||
|
||||
log "Extracting to $PROTON_DIR"
|
||||
mkdir -p "$PROTON_DIR"
|
||||
tar -xzf "$TMPFILE" -C "$PROTON_DIR"
|
||||
ok "$TARGET installed to $INSTALL_PATH"
|
||||
fi
|
||||
|
||||
# ---------- update launch script ----------
|
||||
if [[ ! -f "$LAUNCH_SCRIPT" ]]; then
|
||||
warn "Launch script not found at $LAUNCH_SCRIPT — skipping update."
|
||||
warn "Run battlenet-umu-setup.sh first, or set BATTLENET_LAUNCH_SCRIPT."
|
||||
else
|
||||
CURRENT=$(grep '^export PROTONPATH=' "$LAUNCH_SCRIPT" 2>/dev/null | head -1 | sed 's/.*="\?\([^"]*\)"\?.*/\1/' || echo "(not set)")
|
||||
if [[ "$CURRENT" == "$TARGET" ]]; then
|
||||
skip "Launch script already points to $TARGET"
|
||||
else
|
||||
log "Updating launch script: $CURRENT → $TARGET"
|
||||
sed -i \
|
||||
-e "s|^# Proton version:.*|# Proton version: $TARGET|" \
|
||||
-e "s|^export PROTONPATH=.*|export PROTONPATH=\"$TARGET\"|" \
|
||||
"$LAUNCH_SCRIPT"
|
||||
ok "Launch script updated"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ---------- done ----------
|
||||
echo
|
||||
ok "Done. Active Proton: $TARGET"
|
||||
echo
|
||||
echo " Installed at: $INSTALL_PATH"
|
||||
echo " Launch script: $LAUNCH_SCRIPT"
|
||||
echo
|
||||
echo "Restart Battle.net to use the new Proton version."
|
||||
echo "If anything regresses, re-run with --version=<older-tag> to roll back."
|
||||
Reference in New Issue
Block a user