236 lines
7.8 KiB
Bash
236 lines
7.8 KiB
Bash
#!/usr/bin/env bash
|
|
set -uo pipefail
|
|
|
|
# Configuration:
|
|
# Edit these if needed.
|
|
# Everything else is derived from these values.
|
|
|
|
STEAM_APP_ID="2479810"
|
|
SERVICE_NAME="gzw-eac-fix"
|
|
INSTALL_DIR="$HOME/.local/share/gzw-eac-fix"
|
|
|
|
NOTIFY="false" # set to true to enable desktop notifications via notify-send
|
|
LOG_MAX_LINES="200" # max lines kept in the log file
|
|
POLL_INTERVAL="3" # seconds between file-exists checks after steam validate
|
|
|
|
BLUE='\033[0;34m'
|
|
RED='\033[0;31m'
|
|
NC='\033[0m'
|
|
PREFIX="[${SERVICE_NAME}]"
|
|
|
|
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
LOG_FILE="$INSTALL_DIR/${SERVICE_NAME}.log"
|
|
|
|
# create install dir early so we can log immediately
|
|
mkdir -p "$INSTALL_DIR"
|
|
|
|
_ts() { date "+%Y-%m-%d %H:%M:%S"; }
|
|
|
|
log_info() {
|
|
local msg="$1"
|
|
printf "${BLUE}${PREFIX}${NC} %s\n" "$msg"
|
|
echo "[$(_ts)] [INFO] $msg" >> "$LOG_FILE"
|
|
}
|
|
|
|
log_warn() {
|
|
local msg="$1"
|
|
printf "${BLUE}${PREFIX}${NC} ⚠ %s\n" "$msg"
|
|
echo "[$(_ts)] [WARN] $msg" >> "$LOG_FILE"
|
|
}
|
|
|
|
log_error() {
|
|
local msg="$1"
|
|
printf "${RED}${PREFIX} Error: %s${NC}\n" "$msg" >&2
|
|
echo "[$(_ts)] [ERROR] $msg" >> "$LOG_FILE"
|
|
}
|
|
|
|
die() { log_error "$1"; exit 1; }
|
|
|
|
{
|
|
echo ""
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo " [Gray Zone Warfare EAC Fix] Setup - $(_ts)"
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
} >> "$LOG_FILE"
|
|
|
|
# Guard against downloading individual files instead of cloning the repo
|
|
for required_dir in scripts init; do
|
|
[[ -d "$REPO_DIR/$required_dir" ]] || die \
|
|
"Directory '$required_dir/' not found in $REPO_DIR. " \
|
|
"Please clone the full repository rather than downloading files individually."
|
|
done
|
|
|
|
command -v steam &>/dev/null || die "'steam' not found in PATH - is Steam installed?"
|
|
command -v awk &>/dev/null || die "'awk' not found"
|
|
command -v sed &>/dev/null || die "'sed' not found"
|
|
|
|
find_manifest() {
|
|
local bases=(
|
|
"$HOME/.local/share/Steam"
|
|
"$HOME/.steam/steam"
|
|
"$HOME/.var/app/com.valvesoftware.Steam/.local/share/Steam"
|
|
)
|
|
|
|
declare -A seen
|
|
local all=()
|
|
|
|
for base in "${bases[@]}"; do
|
|
[[ ! -d "$base/steamapps" ]] && continue
|
|
local real; real=$(realpath "$base" 2>/dev/null || echo "$base")
|
|
[[ "${seen[$real]+x}" ]] && continue
|
|
seen["$real"]=1
|
|
all+=("$base/steamapps")
|
|
|
|
local vdf="$base/steamapps/libraryfolders.vdf"
|
|
[[ ! -f "$vdf" ]] && continue
|
|
while IFS= read -r line; do
|
|
local p; p=$(awk -F'"' '/"path"/{print $4}' <<< "$line")
|
|
[[ -n "$p" && -d "$p/steamapps" ]] && all+=("$p/steamapps")
|
|
done < "$vdf"
|
|
done
|
|
|
|
[[ ${#all[@]} -eq 0 ]] && return 1
|
|
|
|
for lib in "${all[@]}"; do
|
|
local m="$lib/appmanifest_${STEAM_APP_ID}.acf"
|
|
[[ -f "$m" ]] && echo "$m" && return 0
|
|
done
|
|
return 1
|
|
}
|
|
|
|
MANIFEST_PATH=$(find_manifest) || die \
|
|
"appmanifest_${STEAM_APP_ID}.acf not found. " \
|
|
"Is Gray Zone Warfare installed? Try: steam://install/${STEAM_APP_ID}"
|
|
|
|
log_info "Found manifest: $MANIFEST_PATH"
|
|
|
|
# Replaces all @@TOKEN@@ placeholders in a source file and writes the result
|
|
# to a destination. This is the single place all config values are baked in.
|
|
|
|
substitute() {
|
|
local src="$1"
|
|
local dst="$2"
|
|
sed \
|
|
-e "s|@@INSTALL_DIR@@|${INSTALL_DIR}|g" \
|
|
-e "s|@@STEAM_APP_ID@@|${STEAM_APP_ID}|g" \
|
|
-e "s|@@MANIFEST_PATH@@|${MANIFEST_PATH}|g" \
|
|
-e "s|@@SERVICE_NAME@@|${SERVICE_NAME}|g" \
|
|
-e "s|@@NOTIFY@@|${NOTIFY}|g" \
|
|
-e "s|@@LOG_MAX_LINES@@|${LOG_MAX_LINES}|g" \
|
|
-e "s|@@POLL_INTERVAL@@|${POLL_INTERVAL}|g" \
|
|
"$src" > "$dst"
|
|
}
|
|
|
|
log_info "Installing scripts to $INSTALL_DIR..."
|
|
|
|
for script in fix.sh watch.sh; do
|
|
substitute "$REPO_DIR/scripts/$script" "$INSTALL_DIR/$script"
|
|
chmod +x "$INSTALL_DIR/$script"
|
|
log_info " Installed $script"
|
|
done
|
|
|
|
detect_init() {
|
|
[[ -d /run/systemd/system ]] || systemctl --version &>/dev/null 2>&1 && { echo "systemd"; return; }
|
|
command -v rc-service &>/dev/null || [[ -x /sbin/openrc ]] && { echo "openrc"; return; }
|
|
command -v runit &>/dev/null || [[ -d /run/runit ]] && { echo "runit"; return; }
|
|
command -v s6-svscan &>/dev/null && { echo "s6"; return; }
|
|
echo "unknown"
|
|
}
|
|
|
|
INIT_SYSTEM=$(detect_init)
|
|
log_info "Detected init system: $INIT_SYSTEM"
|
|
|
|
INIT_SRC="$REPO_DIR/init/$INIT_SYSTEM"
|
|
|
|
case "$INIT_SYSTEM" in
|
|
|
|
systemd)
|
|
SYSTEMD_USER_DIR="$HOME/.config/systemd/user"
|
|
mkdir -p "$SYSTEMD_USER_DIR"
|
|
|
|
for unit in "${SERVICE_NAME}.path" "${SERVICE_NAME}.service"; do
|
|
substitute "$INIT_SRC/$unit" "$SYSTEMD_USER_DIR/$unit"
|
|
log_info " Installed $unit"
|
|
done
|
|
|
|
systemctl --user daemon-reload
|
|
systemctl --user enable --now "${SERVICE_NAME}.path"
|
|
log_info "systemd path watcher enabled."
|
|
echo ""
|
|
systemctl --user status "${SERVICE_NAME}.path" --no-pager
|
|
echo ""
|
|
log_info "Logs: journalctl --user -u ${SERVICE_NAME}.service"
|
|
log_info " or: $LOG_FILE"
|
|
;;
|
|
|
|
openrc)
|
|
command -v inotifywait &>/dev/null || \
|
|
log_warn "inotifywait not found - install inotify-tools"
|
|
|
|
XDG_AUTOSTART_DIR="$HOME/.config/autostart"
|
|
mkdir -p "$XDG_AUTOSTART_DIR"
|
|
substitute "$INIT_SRC/${SERVICE_NAME}.desktop" \
|
|
"$XDG_AUTOSTART_DIR/${SERVICE_NAME}.desktop"
|
|
log_info "XDG autostart entry written."
|
|
log_warn "Watcher starts on next desktop login."
|
|
log_info "Logs: $LOG_FILE"
|
|
;;
|
|
|
|
runit)
|
|
command -v inotifywait &>/dev/null || \
|
|
log_warn "inotifywait not found - install inotify-tools"
|
|
|
|
SV_DIR="$HOME/sv/${SERVICE_NAME}"
|
|
mkdir -p "$SV_DIR/log"
|
|
substitute "$INIT_SRC/run" "$SV_DIR/run"
|
|
substitute "$INIT_SRC/log/run" "$SV_DIR/log/run"
|
|
chmod +x "$SV_DIR/run" "$SV_DIR/log/run"
|
|
mkdir -p "$INSTALL_DIR/log"
|
|
log_info "Runit service written to $SV_DIR"
|
|
log_warn "Link it into your supervision tree to activate, e.g.:"
|
|
log_warn " ln -s $SV_DIR ~/.local/share/runit/sv/${SERVICE_NAME} (Void Linux)"
|
|
log_info "Logs: $INSTALL_DIR/log/"
|
|
;;
|
|
|
|
s6)
|
|
command -v inotifywait &>/dev/null || \
|
|
log_warn "inotifywait not found - install inotify-tools"
|
|
|
|
S6_DIR="$HOME/.config/s6/sv/${SERVICE_NAME}"
|
|
mkdir -p "$S6_DIR"
|
|
substitute "$INIT_SRC/run" "$S6_DIR/run"
|
|
chmod +x "$S6_DIR/run"
|
|
log_info "s6 service written to $S6_DIR"
|
|
log_warn "Link into your scan directory and reload, e.g.:"
|
|
log_warn " ln -s $S6_DIR \$S6_SCAN_DIR/${SERVICE_NAME}"
|
|
log_warn " s6-svscanctl -a \$S6_SCAN_DIR"
|
|
log_info "Logs: $LOG_FILE"
|
|
;;
|
|
|
|
*)
|
|
command -v inotifywait &>/dev/null || \
|
|
log_warn "inotifywait not found - install inotify-tools"
|
|
|
|
XDG_AUTOSTART_DIR="$HOME/.config/autostart"
|
|
mkdir -p "$XDG_AUTOSTART_DIR"
|
|
|
|
# No matching init/ template - write a generic desktop entry directly
|
|
cat > "$XDG_AUTOSTART_DIR/${SERVICE_NAME}.desktop" << EOF
|
|
[Desktop Entry]
|
|
Type=Application
|
|
Name=GZW EAC Fix Watcher
|
|
Exec=${INSTALL_DIR}/watch.sh
|
|
Terminal=false
|
|
X-GNOME-Autostart-enabled=true
|
|
EOF
|
|
log_warn "Unrecognized init system - fell back to XDG autostart."
|
|
log_warn "Watcher starts on next desktop login."
|
|
log_info "Logs: $LOG_FILE"
|
|
;;
|
|
esac
|
|
|
|
echo ""
|
|
log_info "Setup complete."
|
|
log_info "Running initial fix..."
|
|
bash "$INSTALL_DIR/fix.sh"
|