From 54ec7d3f0a36ba18919c0f7941da410acb9a2010 Mon Sep 17 00:00:00 2001 From: Ivan Malison Date: Fri, 22 May 2026 02:48:34 -0700 Subject: [PATCH] feat: add rocket league bakkesmod helper --- dotfiles/lib/bin/rocket-league-bakkesmod | 241 +++++++++++++++++++++++ nixos/games.nix | 4 + 2 files changed, 245 insertions(+) create mode 100755 dotfiles/lib/bin/rocket-league-bakkesmod diff --git a/dotfiles/lib/bin/rocket-league-bakkesmod b/dotfiles/lib/bin/rocket-league-bakkesmod new file mode 100755 index 00000000..43d0b865 --- /dev/null +++ b/dotfiles/lib/bin/rocket-league-bakkesmod @@ -0,0 +1,241 @@ +#!/usr/bin/env bash +set -euo pipefail + +app_name="${HEROIC_ROCKET_LEAGUE_APP_NAME:-Sugar}" +heroic_config_dir="${HEROIC_CONFIG_DIR:-$HOME/.config/heroic}" +game_config="${HEROIC_ROCKET_LEAGUE_CONFIG:-$heroic_config_dir/GamesConfig/$app_name.json}" +installed_json="${HEROIC_LEGENDARY_INSTALLED_JSON:-$heroic_config_dir/legendaryConfig/legendary/installed.json}" +download_url="${BAKKESMOD_SETUP_URL:-https://github.com/bakkesmodorg/BakkesModInjectorCpp/releases/latest/download/BakkesModSetup.zip}" +cache_dir="${XDG_CACHE_HOME:-$HOME/.cache}/rocket-league-bakkesmod" + +die() { + printf 'rocket-league-bakkesmod: %s\n' "$*" >&2 + exit 1 +} + +need_command() { + command -v "$1" >/dev/null 2>&1 || die "missing required command: $1" +} + +jq_value() { + local filter="$1" + local file="$2" + jq -er "$filter // empty" "$file" 2>/dev/null || true +} + +heroic_value() { + local filter="$1" + jq_value ".$app_name.$filter" "$game_config" +} + +installed_value() { + jq_value ".$app_name.$1" "$installed_json" +} + +require_heroic_metadata() { + [ -f "$game_config" ] || die "missing Heroic game config: $game_config" + [ -f "$installed_json" ] || die "missing Legendary installed metadata: $installed_json" +} + +rocket_league_dir() { + local value + value="${ROCKET_LEAGUE_DIR:-}" + if [ -z "$value" ]; then + value="$(installed_value install_path)" + fi + if [ -z "$value" ]; then + value="$HOME/Games/Heroic/rocketleague" + fi + printf '%s\n' "$value" +} + +rocket_league_prefix() { + local value + value="${ROCKET_LEAGUE_PREFIX:-}" + if [ -z "$value" ]; then + value="$(heroic_value winePrefix)" + fi + [ -n "$value" ] || die "could not determine Heroic wine prefix from $game_config" + printf '%s\n' "$value" +} + +rocket_league_proton() { + local value + value="${ROCKET_LEAGUE_PROTON:-}" + if [ -z "$value" ]; then + value="$(heroic_value 'wineVersion.bin')" + fi + [ -n "$value" ] || die "could not determine Heroic Proton binary from $game_config" + printf '%s\n' "$value" +} + +ensure_paths() { + need_command jq + require_heroic_metadata + + rl_dir="$(rocket_league_dir)" + rl_prefix="$(rocket_league_prefix)" + proton_bin="$(rocket_league_proton)" + + [ -d "$rl_dir" ] || die "Rocket League install directory does not exist: $rl_dir" + [ -d "$rl_prefix" ] || die "Rocket League prefix does not exist: $rl_prefix" + [ -x "$proton_bin" ] || die "Proton binary is not executable: $proton_bin" +} + +proton_run() { + export STEAM_COMPAT_DATA_PATH="$rl_prefix" + export STEAM_COMPAT_CLIENT_INSTALL_PATH="${STEAM_COMPAT_CLIENT_INSTALL_PATH:-$HOME/.steam/root}" + export WINEESYNC="${WINEESYNC:-1}" + export WINEFSYNC="${WINEFSYNC:-1}" + + if command -v steam-run >/dev/null 2>&1; then + steam-run "$proton_bin" run "$@" + else + NIXPKGS_ALLOW_UNFREE=1 nix run --impure nixpkgs#steam-run -- "$proton_bin" run "$@" + fi +} + +bakkesmod_exe() { + local candidates=( + "$rl_prefix/pfx/drive_c/Program Files/BakkesMod/BakkesMod.exe" + "$rl_prefix/drive_c/Program Files/BakkesMod/BakkesMod.exe" + "$rl_prefix/pfx/drive_c/users/$USER/AppData/Roaming/bakkesmod/bakkesmod/BakkesMod.exe" + "$rl_prefix/drive_c/users/$USER/AppData/Roaming/bakkesmod/bakkesmod/BakkesMod.exe" + ) + + local candidate + for candidate in "${candidates[@]}"; do + if [ -f "$candidate" ]; then + printf '%s\n' "$candidate" + return 0 + fi + done + + find "$rl_prefix" -iname BakkesMod.exe -print -quit 2>/dev/null +} + +write_bat_launcher() { + local bat_path="$rl_dir/run_with_bakkesmod.bat" + local bakkes_dir="C:\\Program Files\\BakkesMod" + + cat >"$bat_path" </dev/null + status +} + +install() { + ensure_paths + write_bat_launcher >/dev/null + + local silent=false + if [ "${1:-}" = "--silent" ]; then + silent=true + shift + fi + + local setup_exe + setup_exe="$(download_setup)" + printf 'Running BakkesMod installer in Rocket League prefix...\n' + if $silent; then + if ! proton_run "$setup_exe" /VERYSILENT /SUPPRESSMSGBOXES /NORESTART "$@"; then + die "installer failed; use Heroic > Rocket League > Settings > Wine > Run EXE in Prefix and select: $setup_exe" + fi + else + if ! proton_run "$setup_exe" "$@"; then + die "installer failed; use Heroic > Rocket League > Settings > Wine > Run EXE in Prefix and select: $setup_exe" + fi + fi +} + +run() { + ensure_paths + local bat_path + bat_path="$(write_bat_launcher)" + + local bakkes + bakkes="$(bakkesmod_exe)" + [ -n "$bakkes" ] || die "BakkesMod is not installed in the Rocket League prefix; run: rocket-league-bakkesmod install" + + ( + cd "$rl_dir" + proton_run "$bat_path" "$@" + ) +} + +usage() { + cat <<'EOF' +Usage: rocket-league-bakkesmod [rocket-league-args...] + +Commands: + status Show detected Heroic Rocket League, Proton, and BakkesMod paths. + setup Write the Heroic-compatible no-EAC BakkesMod .bat launcher. + install Download and run the BakkesMod installer inside the Rocket League prefix. + Use install --silent for unattended Inno Setup installation. + run Start BakkesMod, then launch Rocket League with -noeac for offline/local play. +EOF +} + +command_name="${1:-status}" +if [ "$#" -gt 0 ]; then + shift +fi + +case "$command_name" in + status) status "$@" ;; + setup) setup "$@" ;; + install) install "$@" ;; + run) run "$@" ;; + help|--help|-h) usage ;; + *) usage >&2; exit 2 ;; +esac diff --git a/nixos/games.nix b/nixos/games.nix index ba250ebe..ee7ece9c 100644 --- a/nixos/games.nix +++ b/nixos/games.nix @@ -50,6 +50,10 @@ in repairXwaylandSocket steamWithXwaylandSocketRepair heroic + legendary-gl + protontricks + steam-run + winetricks ]; hardware.xone.enable = true; }