#!/usr/bin/env bash # Installs Void Sector's launcher for this account on Linux, without sudo: # # curl -fsSL https://playvoidsector.com/install.sh | bash # # It downloads the launcher, checks it against its published SHA-256, and runs it to install itself: with a display, on # the launcher's install screen; without one (over SSH, say), in the terminal. Run it again to repair or update an # install. VOID_SECTOR_UPDATES names another update server (for testing). Options go after "bash -s --": # # --text install in the terminal even with a display # --folder DIR install somewhere other than ~/.local/share/VoidSector # --no-menu, --no-shortcut, --no-command # leave out the app menu entry, the desktop shortcut or the void-sector command # # Every line is inside a function, and the last line calls main: a download cut off part way does nothing at all. set -euo pipefail say() { printf '%s\n' "$*"; } warn() { printf 'Warning: %s\n' "$*" >&2; } fail() { printf 'Void Sector was not installed: %s\n' "$*" >&2 exit 1 } check_system() { [ "$(id -u)" -ne 0 ] || fail "run this as yourself, not as root or with sudo. It installs for your account only." [ "$(uname -s)" = Linux ] || fail "this installer is for Linux. Download the launcher for your system from https://playvoidsector.com" case "$(uname -m)" in x86_64 | amd64) ;; *) fail "Void Sector needs a 64-bit x86 PC (this one is $(uname -m))." ;; esac command -v tar >/dev/null || fail "tar is missing. Install it with your package manager, then run this again." command -v curl >/dev/null || command -v wget >/dev/null || fail "curl or wget is needed to download the launcher." command -v sha256sum >/dev/null || command -v shasum >/dev/null || fail "sha256sum is needed to check the download." } # Void Sector draws with Vulkan: a missing driver doesn't stop the install, but the game won't start without one. check_vulkan() { if command -v vulkaninfo >/dev/null && vulkaninfo --summary >/dev/null 2>&1; then return fi local dir for dir in /usr/share/vulkan/icd.d /etc/vulkan/icd.d /usr/local/share/vulkan/icd.d "${XDG_DATA_HOME:-$HOME/.local/share}/vulkan/icd.d"; do if compgen -G "$dir/*.json" >/dev/null; then return fi done warn "no Vulkan driver was found. Void Sector needs one to run: install your graphics card's Vulkan driver (for example mesa-vulkan-drivers, vulkan-radeon, vulkan-intel or the NVIDIA driver)." } # fetch URL FILE fetch() { if command -v curl >/dev/null; then curl -fsSL --retry 3 -o "$2" "$1" else wget -q -O "$2" "$1" fi } sha256_of() { if command -v sha256sum >/dev/null; then sha256sum "$1" | cut -d' ' -f1 else shasum -a 256 "$1" | cut -d' ' -f1 fi } # download DIR: the launcher's archive and its checksum, checked. Both are fetched with a cache-busting query, and fetched # once more if they don't match, because right after a release a cached checksum can belong to the previous archive. download() { local dir=$1 base=${VOID_SECTOR_UPDATES:-https://updates.playvoidsector.com} local archive="$dir/VoidSectorLauncher-linux.tar.gz" url="${base%/}/download/VoidSectorLauncher-linux.tar.gz" local attempt fresh expected actual for attempt in 1 2; do fresh="fresh=$(date +%s)$$$attempt" say "Downloading the Void Sector launcher..." fetch "$url?$fresh" "$archive" || fail "couldn't download $url. Check your connection and try again." fetch "$url.sha256?$fresh" "$archive.sha256" || fail "couldn't download the launcher's checksum ($url.sha256)." expected=$(cut -d' ' -f1 "$archive.sha256" | tr -d '[:space:]') actual=$(sha256_of "$archive") [[ $expected =~ ^[0-9a-f]{64}$ ]] || fail "the launcher's checksum file is malformed." if [ "$expected" = "$actual" ]; then return fi [ "$attempt" = 1 ] && sleep 5 done fail "the download doesn't match its checksum (expected $expected, got $actual). It may be damaged or tampered with, so nothing was run. Try again in a few minutes." } installed_root() { local data=${XDG_DATA_HOME:-$HOME/.local/share} config=${XDG_CONFIG_HOME:-$HOME/.config} if [ -f "$data/VoidSector/install.json" ]; then printf '%s\n' "$data/VoidSector" elif [ -f "$config/VoidSector/install-folder" ]; then head -n1 "$config/VoidSector/install-folder" fi } main() { local text= local arg for arg in "$@"; do [ "$arg" = --text ] && text=1 done if [ -z "${DISPLAY:-}${WAYLAND_DISPLAY:-}" ]; then text=1 fi check_system check_vulkan # (a global, for the trap that runs after main returns; the launcher copies itself out before it hands over) scratch=$(mktemp -d "${TMPDIR:-/tmp}/void-sector-install.XXXXXX") trap 'rm -rf "${scratch:-}"' EXIT local dir=$scratch download "$dir" tar -xzf "$dir/VoidSectorLauncher-linux.tar.gz" -C "$dir" || fail "the download couldn't be unpacked." local launcher="$dir/VoidSector/VoidSectorLauncher.x86_64" [ -x "$launcher" ] || fail "the download has no launcher in it." # (another update server, for testing: the launcher installs itself from the same one) if [ -n "${VOID_SECTOR_UPDATES:-}" ]; then set -- "$@" --updates "${VOID_SECTOR_UPDATES%/}/" fi if [ -n "$text" ]; then say "Installing in the terminal (no display)." # (stdin is this script when it's piped to bash: the launcher asks its questions on the terminal instead) local status=0 "$launcher" --headless --quiet -- --install "$@" /dev/null; then setsid --wait "$launcher" -- --install "$@" "$dir/launcher.log" 2>&1 || status=$? else "$launcher" -- --install "$@" "$dir/launcher.log" 2>&1 || status=$? fi local root root=$(installed_root) if [ -z "$root" ] || [ ! -f "$root/install.json" ]; then [ "$status" -eq 0 ] || tail -n 20 "$dir/launcher.log" >&2 fail "the installer closed before it finished. Run this again to install." fi say "Void Sector is installed. Start it from your app menu, or run: void-sector" case ":$PATH:" in *":${XDG_BIN_HOME:-$HOME/.local/bin}:"*) ;; *) say "(${XDG_BIN_HOME:-$HOME/.local/bin} isn't on your PATH yet, so until it is, run: ${XDG_BIN_HOME:-$HOME/.local/bin}/void-sector)" ;; esac } # (in braces: cut off anywhere before the closing brace, this line is a syntax error, so nothing runs) { main "$@"; }