|
|
@@ -0,0 +1,144 @@
|
|
|
+#!/usr/bin/env bash
|
|
|
+
|
|
|
+set -u
|
|
|
+
|
|
|
+if [[ $# -lt 2 ]]; then
|
|
|
+ echo "Usage: $0 <Steam AppID> <process regex>" >&2
|
|
|
+ exit 2
|
|
|
+fi
|
|
|
+
|
|
|
+APPID="$1"
|
|
|
+PROCESS_REGEX="$2"
|
|
|
+
|
|
|
+START_TIMEOUT="${START_TIMEOUT:-120}"
|
|
|
+EXIT_STABLE_TIME="${EXIT_STABLE_TIME:-3}"
|
|
|
+
|
|
|
+SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
|
|
+LOG_FILE="${SCRIPT_DIR}/steam-game.log"
|
|
|
+
|
|
|
+log() {
|
|
|
+ printf '[%s] [STEAM:%s] %s\n' \
|
|
|
+ "$(date '+%Y-%m-%d %H:%M:%S')" \
|
|
|
+ "${APPID}" \
|
|
|
+ "$*" >> "${LOG_FILE}"
|
|
|
+}
|
|
|
+
|
|
|
+if ! command -v steam >/dev/null 2>&1; then
|
|
|
+ log "ERROR: steam command not found"
|
|
|
+ exit 127
|
|
|
+fi
|
|
|
+
|
|
|
+#
|
|
|
+# PIDs du jeu.
|
|
|
+#
|
|
|
+# On inspecte /proc nous-mêmes afin d'éviter que pgrep -f ne matche
|
|
|
+# accidentellement le wrapper avec le regex passé en argument.
|
|
|
+#
|
|
|
+game_pids() {
|
|
|
+ local proc
|
|
|
+ local pid
|
|
|
+ local cmdline
|
|
|
+ local -a argv
|
|
|
+
|
|
|
+ for proc in /proc/[0-9]*; do
|
|
|
+ pid="${proc##*/}"
|
|
|
+
|
|
|
+ # Ne jamais nous matcher nous-mêmes.
|
|
|
+ [[ "${pid}" == "$$" ]] && continue
|
|
|
+
|
|
|
+ [[ -r "${proc}/cmdline" ]] || continue
|
|
|
+
|
|
|
+ argv=()
|
|
|
+
|
|
|
+ mapfile -d '' -t argv < "${proc}/cmdline" 2>/dev/null || true
|
|
|
+
|
|
|
+ [[ ${#argv[@]} -gt 0 ]] || continue
|
|
|
+
|
|
|
+ cmdline="${argv[*]}"
|
|
|
+
|
|
|
+ if [[ "${cmdline}" =~ ${PROCESS_REGEX} ]]; then
|
|
|
+ printf '%s\n' "${pid}"
|
|
|
+ fi
|
|
|
+ done
|
|
|
+}
|
|
|
+
|
|
|
+terminate_game() {
|
|
|
+ local -a pids
|
|
|
+
|
|
|
+ mapfile -t pids < <(game_pids)
|
|
|
+
|
|
|
+ if [[ ${#pids[@]} -gt 0 ]]; then
|
|
|
+ log "Stopping game processes: ${pids[*]}"
|
|
|
+
|
|
|
+ kill -TERM "${pids[@]}" 2>/dev/null || true
|
|
|
+
|
|
|
+ sleep 3
|
|
|
+
|
|
|
+ mapfile -t pids < <(game_pids)
|
|
|
+
|
|
|
+ if [[ ${#pids[@]} -gt 0 ]]; then
|
|
|
+ log "Force stopping remaining processes: ${pids[*]}"
|
|
|
+ kill -KILL "${pids[@]}" 2>/dev/null || true
|
|
|
+ fi
|
|
|
+ fi
|
|
|
+}
|
|
|
+
|
|
|
+#
|
|
|
+# Important pour la suite :
|
|
|
+# si Sunshine arrête ce wrapper, on ferme également le jeu.
|
|
|
+#
|
|
|
+trap 'log "Wrapper received termination signal"; terminate_game; exit 143' \
|
|
|
+ TERM INT HUP
|
|
|
+
|
|
|
+log "Launching Steam AppID ${APPID}"
|
|
|
+log "Process regex: ${PROCESS_REGEX}"
|
|
|
+
|
|
|
+nohup steam -applaunch "${APPID}" \
|
|
|
+ >> "${LOG_FILE}" 2>&1 &
|
|
|
+
|
|
|
+#
|
|
|
+# Attendre que le vrai processus du jeu apparaisse.
|
|
|
+#
|
|
|
+start_time="${SECONDS}"
|
|
|
+
|
|
|
+while true; do
|
|
|
+ mapfile -t pids < <(game_pids)
|
|
|
+
|
|
|
+ if [[ ${#pids[@]} -gt 0 ]]; then
|
|
|
+ log "Game detected: ${pids[*]}"
|
|
|
+ break
|
|
|
+ fi
|
|
|
+
|
|
|
+ if (( SECONDS - start_time >= START_TIMEOUT )); then
|
|
|
+ log "ERROR: game did not appear within ${START_TIMEOUT}s"
|
|
|
+ exit 124
|
|
|
+ fi
|
|
|
+
|
|
|
+ sleep 1
|
|
|
+done
|
|
|
+
|
|
|
+#
|
|
|
+# Rester vivant aussi longtemps que le jeu.
|
|
|
+#
|
|
|
+missing_since=""
|
|
|
+
|
|
|
+while true; do
|
|
|
+ mapfile -t pids < <(game_pids)
|
|
|
+
|
|
|
+ if [[ ${#pids[@]} -gt 0 ]]; then
|
|
|
+ missing_since=""
|
|
|
+ else
|
|
|
+ if [[ -z "${missing_since}" ]]; then
|
|
|
+ missing_since="${SECONDS}"
|
|
|
+ fi
|
|
|
+
|
|
|
+ if (( SECONDS - missing_since >= EXIT_STABLE_TIME )); then
|
|
|
+ log "Game exited"
|
|
|
+ break
|
|
|
+ fi
|
|
|
+ fi
|
|
|
+
|
|
|
+ sleep 1
|
|
|
+done
|
|
|
+
|
|
|
+exit 0
|