]> vilimpoc.org git repositories - bl2-split/blob - README.md
Simultaneous launch + CAPS mouse-wiggle banner, move windows after 30s; fix kill status message
[bl2-split] / README.md
1 # Borderlands 2 — 2-player split-screen / dual-monitor co-op on Linux
2
3 Runs **two local instances** of Borderlands 2 that connect to each other over
4 Goldberg's emulated Steam LAN, so two people can play co-op on one PC — each with
5 their own controller, save, and screen. Tested on **Arch + KDE Plasma 6 (Wayland)**.
6
7 - **Two monitors:** one instance fullscreen on each (auto-detected).
8 - **One monitor:** side-by-side split.
9 - Each Xbox controller drives only its own instance.
10
11 > BL2 has no native PC split-screen; this launches two copies networked over LAN.
12 > Only legitimate because you own the game. No game files or saves are committed here.
13
14 ![Two Borderlands 2 instances running co-op across two monitors, each on its own main menu in the shared LAN lobby with per-player Xbox controller prompts](sxs.jpg)
15
16 ## Requirements
17
18 - **Borderlands 2 installed via Steam, forced to the Windows build under Proton**
19   (see setup step 1). The native Linux (Aspyr) build is supported as a fallback but
20   is crash-prone with two instances — Proton is the recommended path.
21 - Packages: `umu-launcher`, `gamescope` *(optional)*, `qt6-tools` (for `qdbus6`),
22   `bubblewrap`, `libarchive` (`bsdtar`), `curl`, `binutils` (`strings`).
23   ```
24   sudo pacman -S umu-launcher qt6-tools bubblewrap libarchive curl binutils
25   ```
26 - *Optional:* `gamemode` (+ `lib32-gamemode`) — the script runs each game under
27   `gamemoderun` if present (performance CPU governor while playing). Not required.
28 - Two Xbox controllers (any two distinguishable pads).
29
30 ## Setup
31
32 1. **Point Steam at the Windows build.** Steam → *Borderlands 2 → Properties →
33    Compatibility →* tick **"Force the use of a specific Steam Play compatibility
34    tool"** → pick **Proton Experimental** (or a stable Proton). Steam re-downloads
35    the Windows depot. (To use the native Linux build instead, skip this — the script
36    auto-detects which is installed.)
37
38 2. **Build the two copies:**
39    ```
40    cd bl2-split
41    ./bl2-splitscreen.sh check     # verifies prerequisites; shows detected mode
42    ./bl2-splitscreen.sh setup     # downloads Goldberg + builds p1/ and p2/
43    ```
44    `setup` auto-downloads the Goldberg emulator (it is **not** committed to this
45    repo) and builds two symlink-mirror copies of the game with per-player Steam
46    identities. First `run` also makes umu download Proton + build each prefix (slow,
47    one time).
48
49 3. **Play** (turn on both controllers first):
50    ```
51    ./bl2-splitscreen.sh run
52    ```
53    Both instances launch at once. While they load, **wiggle the mouse** until both
54    reach the main menu (the script prints a loud reminder), and leave the windows
55    alone — after ~30 s the script moves each onto its screen (fullscreen per monitor
56    with two displays, side-by-side with one). In-game: **Player 1** *Play → host over
57    LAN*; **Player 2** *Play → Join → pick the LAN game*. `Ctrl-C` kills both.
58
59 ## Commands
60
61 | Command | Does |
62 |---|---|
63 | `./bl2-splitscreen.sh fetch` | download the Goldberg emulator into `goldberg/` |
64 | `./bl2-splitscreen.sh check` | verify prerequisites; print the detected mode |
65 | `./bl2-splitscreen.sh setup` | fetch Goldberg + build `p1/`, `p2/` |
66 | `./bl2-splitscreen.sh run`   | launch both instances + place windows |
67 | `./bl2-splitscreen.sh tile`  | re-place the two windows |
68 | `./bl2-splitscreen.sh kill`  | terminate all running Borderlands 2 instances |
69 | `./bl2-splitscreen.sh clean` | kill instances, then remove `p1/`, `p2/` (copies + saves + prefixes) |
70
71 Useful env overrides: `MODE=native|proton`, `DISPLAY_MODE=dual|split`,
72 `ISOLATION=bwrap|sdl`, `SPLASH_WAIT=<secs>`, `STAGGER=<secs>`.
73
74 ## How it works
75
76 | Concern | Solution |
77 |---|---|
78 | Two instances at once | Each copy uses **Goldberg** (`steam_api.dll`) instead of real Steam; they connect over emulated LAN |
79 | Goldberg actually loads | The `.exe` is copied **real** (not symlinked) so Wine loads DLLs from our dir, not the real install's `steam_api.dll` |
80 | Two different LAN players | Per-copy `force_account_name.txt` + `force_steamid.txt` |
81 | No startup crash | `steam_interfaces.txt` extracted from the original Steam lib per copy |
82 | Separate saves | Each instance has its own Proton prefix (`p1/prefix`, `p2/prefix`) |
83 | Co-op finds each other | Goldberg `custom_broadcasts.txt` → `127.0.0.1` (broadcast doesn't cross the two Proton containers) |
84 | Skips slow "Creating online session" | Goldberg `configs.main.ini` → `offline=1` |
85 | Windowed at the right size | `-windowed -ResX -ResY`; **no gamescope** (it hides raw controllers from nested clients) |
86 | One controller per instance | **bwrap** masks the other pad's `/dev/input` nodes (the Xbox pads are evdev-only, no hidraw) |
87 | Window placement | KWin script via `qdbus6` — one monitor each (dual) or side-by-side (single) |
88 | No intro-logo wait | Intro movies disabled in each prefix's `WillowEngine.ini` |
89 | No 13 GB duplication | `cp -as` symlink-mirror; only `steam_api.dll` + the `.exe` are real copies |
90
91 ## What's in git (and what isn't)
92
93 **Committed** (enough for anyone to reproduce):
94 ```
95 bl2-splitscreen.sh     the launcher/setup script
96 README.md              this file
97 .gitignore
98 goldberg/.gitkeep      empty dir; setup downloads binaries into it
99 p1/.gitkeep p2/.gitkeep
100 ```
101
102 **Never committed** (`.gitignore`):
103 - `goldberg/steam_api.dll`, `goldberg/libsteam_api.so` — the Goldberg emulator
104   binaries. They implement Steam's proprietary API, so they aren't redistributed
105   here; `setup` downloads them from the upstream releases (gbe_fork / Mr_Goldberg).
106 - `p1/`, `p2/` (except `.gitkeep`) — the game copies, **your save games**, and Wine
107   prefixes. Machine-specific and large.
108 - `*.log`.
109
110 So another person clones the repo, forces Proton on their own BL2 in Steam, runs
111 `./bl2-splitscreen.sh setup`, and everything else is pulled/generated locally.
112
113 ## Troubleshooting
114
115 - **Both pads control both screens / keyboard controls both:** the games read input
116   globally. Controllers are isolated by `bwrap` device-masking (default). Keyboard &
117   mouse are *not* isolated — use a controller per player; kb/mouse is only for menus.
118 - **A pad drives the wrong screen or none:** ensure `ISOLATION=bwrap` (default). If
119   **Steam is running**, its Steam Input virtual pads can interfere — quit Steam.
120 - **Stuck on "Creating online session":** should be quick with `offline=1` (set by
121   setup). If a co-op *join* ever breaks, remove the offline setting:
122   `rm p{1,2}/game/Binaries/Win32/steam_settings/configs.main.ini`
123 - **They don't see each other on LAN:** Player 1 hosts first (the script staggers
124   launches). Discovery uses `custom_broadcasts.txt` (localhost).
125 - **The 2nd instance is visible but stuck on the loading screen — and only advances
126   when you jiggle the mouse.** Root cause: BL2's `bPauseOnLossOfFocus=TRUE` — the
127   game **pauses itself whenever its window isn't focused**. In split-screen only one
128   window is focused at a time, so the unfocused instance freezes until an input event
129   wakes it. `setup`/`run` patch each prefix's `WillowEngine.ini` to
130   `bPauseOnLossOfFocus=FALSE` so every instance keeps running unfocused. (This was
131   *not* CPU scaling, entropy, or window occlusion — those were dead ends.) The
132   instances also share a DXVK shader cache so the 2nd reuses the 1st's compiled
133   shaders; `STAGGER=45` further separates their loads if a cold first run is slow.
134 - **Two soundtracks at once:** each instance sets `bMuteAudioWhenNotInFocus=TRUE`, so
135   only the focused window plays audio — the sound follows whichever instance you're
136   focused on, instead of both playing together.
137 - **In-game "Quit Borderlands 2 → Yes" does nothing / hangs:** the game's shutdown
138   path stalls under Goldberg (Steam-networking cleanup, worse with offline mode).
139   Don't use in-game Quit — close with **`./bl2-splitscreen.sh kill`** or **Ctrl-C**
140   in the run terminal (safe: you're at the menu, nothing is saving).
141 - **Ctrl-C / kill left something running:** `./bl2-splitscreen.sh kill` tears down
142   the whole game + Proton/Wine tree.
143 - **A window won't sit on its monitor:** re-run `./bl2-splitscreen.sh tile`; raise
144   `SPLASH_WAIT` if it fires before the game settles.
145 - **Reset everything:** `./bl2-splitscreen.sh clean` (removes copies + saves; the
146   real Steam install is untouched).
147
148 ## Native (Aspyr Linux) fallback
149
150 If Steam has the native Linux build installed, the script auto-detects `native` mode:
151 it uses the **classic Mr_Goldberg** `.so` (gbe_fork crashes that old binary), runs
152 inside the Steam scout runtime, and isolates controllers the same way. It works, but
153 the second instance is prone to crashing — prefer the Proton path.