| `./bl2-splitscreen.sh setup` | fetch Goldberg + build `p1/`, `p2/` |
| `./bl2-splitscreen.sh run` | launch both instances + place windows |
| `./bl2-splitscreen.sh tile` | re-place the two windows |
-| `./bl2-splitscreen.sh clean` | remove `p1/`, `p2/` (copies + saves + prefixes) |
+| `./bl2-splitscreen.sh kill` | terminate all running Borderlands 2 instances |
+| `./bl2-splitscreen.sh clean` | kill instances, then remove `p1/`, `p2/` (copies + saves + prefixes) |
Useful env overrides: `MODE=native|proton`, `DISPLAY_MODE=dual|split`,
`ISOLATION=bwrap|sdl`, `SPLASH_WAIT=<secs>`, `STAGGER=<secs>`.
`rm p{1,2}/game/Binaries/Win32/steam_settings/configs.main.ini`
- **They don't see each other on LAN:** Player 1 hosts first (the script staggers
launches). Discovery uses `custom_broadcasts.txt` (localhost).
+- **The 2nd instance takes ages to reach the menu:** the two share a DXVK shader
+ cache (`dxvk-cache/`) so the 2nd reuses the 1st's shaders; the first-ever run
+ still compiles them. If it's still slow, raise the gap between launches so the 1st
+ is fully loaded before the 2nd starts: `STAGGER=45 ./bl2-splitscreen.sh run`.
+- **Ctrl-C / kill left something running:** `./bl2-splitscreen.sh kill` tears down
+ the whole game + Proton/Wine tree.
- **A window won't sit on its monitor:** re-run `./bl2-splitscreen.sh tile`; raise
`SPLASH_WAIT` if it fires before the game settles.
- **Reset everything:** `./bl2-splitscreen.sh clean` (removes copies + saves; the
else
wd="$pg/Binaries/Win32"
patch_proton_config "$BASE/p$n/prefix" # skip intro movies (if prefix exists)
- env=( "WINEPREFIX=$BASE/p$n/prefix" "GAMEID=0" "STORE=none" )
+ mkdir -p "$BASE/dxvk-cache"
+ env=( "WINEPREFIX=$BASE/p$n/prefix" "GAMEID=0" "STORE=none"
+ "UMU_RUNTIME_UPDATE=0" # skip umu's startup update check
+ # Shared D3D shader cache: the 2nd instance reuses shaders the 1st already
+ # compiled instead of recompiling them while the 1st is using the GPU.
+ "DXVK_STATE_CACHE_PATH=$BASE/dxvk-cache" )
# Only use the SDL VID/PID filter in "sdl" mode. With bwrap masking it is
# redundant AND can over-filter (it wrongly dropped the 360 pad), so skip it.
[ "$ISOLATION" = sdl ] && env+=( "SDL_GAMECONTROLLER_IGNORE_DEVICES_EXCEPT=$vidpid" )
say "${c_dim}Windows settle onto $where ~${SPLASH_WAIT}s in (after the splash)."
say "Re-place any time with: ./bl2-splitscreen.sh tile${c_rst}"
say ""; say "Press Ctrl-C to kill both instances."
- trap 'kill "$pid1" "$pid2" 2>/dev/null' INT TERM
+ # Killing $pid1/$pid2 only hits the top of each tree; the game runs deeper inside
+ # umu/pressure-vessel and survives. kill_instances tears down the whole tree.
+ trap 'echo; kill_instances; exit 130' INT TERM
wait "$pid1" "$pid2"
}
+# ------------------------------------------------------------------ kill ----
+# Terminate every Borderlands 2 process we launched (game exe + umu/Proton/Wine
+# tree for our prefixes), SIGTERM first then SIGKILL. Scoped to our BASE dir so it
+# won't touch unrelated Wine apps.
+kill_instances() {
+ local sig
+ for sig in TERM KILL; do
+ pkill -"$sig" -f 'Borderlands2\.exe' 2>/dev/null # proton game
+ pkill -"$sig" -x 'Borderlands2' 2>/dev/null # native game
+ pkill -"$sig" -f "$BASE/p[12]/" 2>/dev/null # umu/proton/wine for our copies+prefixes
+ [ "$sig" = TERM ] && sleep 2
+ done
+}
+
+cmd_kill() {
+ # Match the process NAME (comm) as a substring, not the full cmdline - otherwise
+ # helper shells that merely have the game path in their args get counted. This
+ # matches "Borderlands2.ex" (Proton, 15-char truncated) and "Borderlands2".
+ pgrep 'Borderlands2' >/dev/null || { ok "No Borderlands 2 instances running."; return 0; }
+ say "Killing Borderlands 2 instances..."
+ kill_instances
+ local left; left=$(pgrep -c 'Borderlands2' 2>/dev/null || echo 0)
+ [ "$left" = 0 ] && ok "All instances killed." || warn "$left process(es) still lingering."
+}
+
# ------------------------------------------------------------------ clean ---
-cmd_clean() { say "Removing generated copies/saves (real game untouched)..."; rm -rf "$BASE/p1" "$BASE/p2"; ok "Done."; }
+cmd_clean() { cmd_kill; say "Removing generated copies/saves (real game untouched)..."; rm -rf "$BASE/p1" "$BASE/p2"; ok "Done."; }
case "${1:-}" in
fetch) cmd_fetch ;;
setup) cmd_setup ;;
run) cmd_run ;;
tile) cmd_tile ;;
+ kill) cmd_kill ;;
clean) cmd_clean ;;
- *) say "Usage: $0 {fetch|check|setup|run|tile|clean} (MODE=native|proton to force)"; exit 1 ;;
+ *) say "Usage: $0 {fetch|check|setup|run|tile|kill|clean} (MODE=native|proton to force)"; exit 1 ;;
esac