Skip to content

Commit

Permalink
fix: update steam-launch
Browse files Browse the repository at this point in the history
  • Loading branch information
simonwjackson committed Dec 17, 2024
1 parent c1d7a62 commit 8c464ea
Show file tree
Hide file tree
Showing 2 changed files with 210 additions and 58 deletions.
61 changes: 32 additions & 29 deletions packages/steam-launch/default.nix
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
{
bash,
coreutils,
gawk,
gnugrep,
gnused,
jq,
pkgs,
lib,
resholve,
steam-run,
stdenv,
binutils,
}:
resholve.mkDerivation {
Expand All @@ -17,11 +10,11 @@ resholve.mkDerivation {
src = ./.;

buildInputs = [
bash
gnused
jq
steam-run
binutils
pkgs.bash
pkgs.binutils
pkgs.gnused
pkgs.jq
pkgs.steam-run
];

installPhase = ''
Expand All @@ -31,25 +24,35 @@ resholve.mkDerivation {
solutions = {
steam-launch = {
scripts = ["bin/steam-launch"];
interpreter = "${bash}/bin/bash";
interpreter = "${pkgs.bash}/bin/bash";
inputs = [
"${gnused}/bin"
"${jq}/bin"
"${steam-run}/bin"
"${coreutils}/bin"
"${gawk}/bin"
"${gnugrep}/bin"
"${binutils}/bin"
"${pkgs.binutils}/bin"
"${pkgs.coreutils}/bin"
"${pkgs.findutils}/bin"
"${pkgs.gawk}/bin"
"${pkgs.gnugrep}/bin"
"${pkgs.gnused}/bin"
"${pkgs.gum}/bin"
"${pkgs.jq}/bin"
"${pkgs.steam-run}/bin"
];
execer = [
"cannot:${coreutils}/bin/basename"
"cannot:${coreutils}/bin/cat"
"cannot:${coreutils}/bin/sleep"
"cannot:${gnugrep}/bin/grep"
"cannot:${gnused}/bin/sed"
"cannot:${gawk}/bin/awk"
"cannot:${binutils}/bin/strings"
"cannot:${steam-run}/bin/steam-run"
"cannot:${pkgs.binutils}/bin/strings"
"cannot:${pkgs.coreutils}/bin/basename"
"cannot:${pkgs.coreutils}/bin/cat"
"cannot:${pkgs.coreutils}/bin/cut"
"cannot:${pkgs.coreutils}/bin/dirname"
"cannot:${pkgs.coreutils}/bin/head"
"cannot:${pkgs.coreutils}/bin/mkdir"
"cannot:${pkgs.coreutils}/bin/sleep"
"cannot:${pkgs.coreutils}/bin/sort"
"cannot:${pkgs.coreutils}/bin/wc"
"cannot:${pkgs.findutils}/bin/find"
"cannot:${pkgs.gawk}/bin/awk"
"cannot:${pkgs.gnugrep}/bin/grep"
"cannot:${pkgs.gnused}/bin/sed"
"cannot:${pkgs.gum}/bin/gum"
"cannot:${pkgs.steam-run}/bin/steam-run"
];
fake = {
external = ["steam" "pgrep" "setsid"];
Expand Down
207 changes: 178 additions & 29 deletions packages/steam-launch/steam-launch.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,39 @@ Usage:
Options:
--proton <proton_path> Path to Proton
--debug Enable debug output
-h, --help Show this screen.
Arguments:
<appid> Steam App ID
EOF
}

# Debug mode flag
DEBUG=0

# Simple argument parsing
if [[ $# -eq 0 ]]; then
show_help
exit 1
fi

debug_log() {
if [[ $DEBUG -eq 1 ]]; then
echo "🔍 DEBUG: $*" >&2
fi
}

while [[ $# -gt 0 ]]; do
case $1 in
--proton)
PROTON_PATH="$2"
shift 2
;;
--debug)
DEBUG=1
shift
;;
-h | --help)
show_help
exit 0
Expand Down Expand Up @@ -63,7 +77,7 @@ APPINFO_FILE="${HOME}/.local/share/Steam/appcache/appinfo.vdf"

check_steam_running() {
if ! pgrep -x "steam" >/dev/null; then
echo "Steam is not running. Starting Steam in silent mode..."
gum spin --spinner dot --title "Steam is not running. Starting Steam in silent mode..." -- sleep 5
setsid steam -silent </dev/null &>/dev/null &
sleep 5
fi
Expand Down Expand Up @@ -92,7 +106,7 @@ find_library() {
done <"$LIBRARY_FOLDERS_FILE"

if [[ -z "$library_path" ]]; then
echo "Error: Unable to find library for AppID $appid" >&2
gum style --foreground 1 "Error: Unable to find library for AppID $appid"
exit 1
fi

Expand All @@ -106,7 +120,7 @@ find_game_dir() {
local manifest_file="${library}/steamapps/appmanifest_${appid}.acf"

if [[ ! -f "$manifest_file" ]]; then
echo "Error: Manifest file not found for AppID ${appid}" >&2
gum style --foreground 1 "Error: Manifest file not found for AppID ${appid}"
exit 1
fi

Expand All @@ -115,58 +129,193 @@ find_game_dir() {
echo "${library}/steamapps/common/${install_dir}"
}

# Function to find the game's executable
# Function to find the game's executable from the manifest file
find_game_exe() {
local app_path="$1"
local executable

executable=$(strings "$APPINFO_FILE" | awk -v app_path="$app_path" '
$0 ~ app_path {
while (getline) {
if ($0 ~ /launch/) {
while (getline) {
if ($0 ~ /executable/) {
getline
print
exit
}
}
}
}
}')
local library="$1"
local appid="$2"
local manifest_file="${library}/steamapps/appmanifest_${appid}.acf"
local executable=""

# Check if manifest file exists
if [[ ! -f "$manifest_file" ]]; then
gum style --foreground 1 "Error: Manifest file not found: ${manifest_file}"
return 1
fi

# First, get the installdir from the manifest
local installdir
installdir=$(grep -Po '"installdir"\s*"\K[^"]*' "$manifest_file")
if [[ -z "$installdir" ]]; then
gum style --foreground 1 "Error: Could not find installdir in manifest"
return 1
fi

# Construct the full app path
local app_path="${library}/steamapps/common/${installdir}"
if [[ ! -d "$app_path" ]]; then
gum style --foreground 1 "Error: Game directory not found: ${app_path}"
return 1
fi

# Try multiple methods to find the executable

# Method 1: Parse the manifest file for the executable
executable=$(awk -F'"' '
/^[[:space:]]*"launch"/ {in_launch=1; next}
in_launch && /^[[:space:]]*"[0-9]+"/ {in_config=1; next}
in_launch && in_config && /executable/ {print $4; exit}
/^[[:space:]]*}/ {if(in_config) in_config=0; else if(in_launch) in_launch=0}
' "$manifest_file")

# Method 2: Look for .exe files in the game directory
if [[ -z "$executable" ]]; then
echo "Error: Unable to find executable for AppID ${app_path}" >&2
exit 1
# First, try to find an exe with the same name as the installdir
if [[ -f "${app_path}/${installdir}.exe" ]]; then
executable="${installdir}.exe"
else
# Look for common executable names
for exe in launcher.exe game.exe start.exe $(basename "${installdir}").exe; do
if [[ -f "${app_path}/${exe}" ]]; then
executable="$exe"
break
fi
done
fi
fi

# Method 3: Find all .exe files and try to identify the main one
if [[ -z "$executable" ]]; then
# Find all .exe files in the directory, excluding common utility executables
local exe_files
exe_files=$(find "$app_path" -maxdepth 2 -type f -name "*.exe" \
! -name "unins*.exe" \
! -name "*crash*.exe" \
! -name "*update*.exe" \
! -name "redist*.exe" \
! -name "UnityCrash*.exe" \
-printf "%P\n" | sort) # Using %P instead of %f to include subdirectory

if [[ $DEBUG -eq 1 ]]; then
echo "🔍 DEBUG: Found executables:" >&2
echo "$exe_files" | sed 's/^/🔍 DEBUG: /' >&2
fi

# If there's only one exe, use that
if [[ $(echo "$exe_files" | wc -l) -eq 1 ]]; then
executable="$exe_files"
# If there are multiple exes, try to find the most likely main one
elif [[ -n "$exe_files" ]]; then
# Look for executables with common main program patterns
while IFS= read -r exe; do
if [[ "${exe,,}" =~ (game|start|launch|bin|main|play|run|client) ]]; then
executable="$exe"
break
fi
done <<<"$exe_files"

# If still not found, use the largest executable
if [[ -z "$executable" ]]; then
executable=$(find "$app_path" -maxdepth 2 -type f -name "*.exe" \
! -name "unins*.exe" \
! -name "*crash*.exe" \
! -name "*update*.exe" \
! -name "redist*.exe" \
! -name "UnityCrash*.exe" \
-printf "%s %P\n" | sort -nr | head -n1 | cut -d' ' -f2-)
fi
fi
fi

if [[ -z "$executable" ]]; then
gum style --foreground 1 "Error: Unable to find executable for app ${appid}"
return 1
fi

# Verify the executable exists
if [[ ! -f "${app_path}/${executable}" ]]; then
gum style --foreground 1 "Error: Found executable name but file does not exist: ${app_path}/${executable}"
return 1
fi

echo "$executable"
return 0
}

# Print debug environment info
debug_log "Environment variables:"
debug_log "STEAM_HOME=$STEAM_HOME"
debug_log "STEAM_HOME_APPS_PATH=$STEAM_HOME_APPS_PATH"
debug_log "LIBRARY_FOLDERS_FILE=$LIBRARY_FOLDERS_FILE"
debug_log "APPINFO_FILE=$APPINFO_FILE"

# Find the correct Steam library
STEAM_GAME_LIBRARY=$(find_library "$SteamAppId")
echo "Using Steam library: $STEAM_GAME_LIBRARY"
gum style --foreground 4 "Using Steam library: $STEAM_GAME_LIBRARY"

# Find game directory and executable
APP_PATH=$(find_game_dir "$STEAM_GAME_LIBRARY" "$SteamAppId")
APP_EXEC=$(find_game_exe "$(basename "$APP_PATH")")
debug_log "Game directory: $APP_PATH"

APP_EXEC=$(find_game_exe "$STEAM_GAME_LIBRARY" "$SteamAppId")
debug_log "Game executable: $APP_EXEC"

APP_EXEC_FULL_PATH="${APP_PATH}/${APP_EXEC}"
debug_log "Full executable path: $APP_EXEC_FULL_PATH"

# Export required variables
export STEAM_COMPAT_CLIENT_INSTALL_PATH="${STEAM_GAME_LIBRARY}/steamapps"
export STEAM_COMPAT_DATA_PATH="${STEAM_GAME_LIBRARY}/steamapps/compatdata/${SteamAppId}"

# Check for compatdata directory and create base structure if missing
if [[ ! -d "${STEAM_COMPAT_DATA_PATH}" ]] || [[ ! -d "${STEAM_COMPAT_DATA_PATH}/pfx" ]]; then
gum style \
--border double \
--border-foreground 3 \
--padding "1 2" \
--margin 1 \
"Compatibility data not found for this game!" \
"Please follow these steps:" \
"1. Open Steam" \
"2. Right-click the game" \
"3. Select Properties" \
"4. Under Compatibility, check 'Force the use of a specific Steam Play compatibility tool'" \
"5. Launch the game once through Steam" \
"6. Close the game" \
"7. Try running this launcher again"

if gum confirm "Would you like to open Steam to the game's properties?" --affirmative="Yes" --negative="No"; then
steam "steam://nav/games/details/${SteamAppId}"
gum style --foreground 3 "Steam should now be open to the game's page." \
"Please right-click the game and select Properties to continue setup."
fi
exit 1
fi

# Proton executable
PROTON_EXEC="${PROTON_PATH}/proton"

# Change to the application directory
if ! cd "${APP_PATH}"; then
echo "Error: Unable to change to directory ${APP_PATH}" >&2
exec_dir=$(dirname "${APP_PATH}/${APP_EXEC}")
debug_log "Changing to executable directory: $exec_dir"
if ! cd "${exec_dir}"; then
gum style --foreground 1 "Error: Unable to change to directory ${exec_dir}"
exit 1
fi

# Ensure base directory structure exists
mkdir -p "${STEAM_COMPAT_DATA_PATH}/pfx"

# Debug launch info
debug_log "Launch configuration:"
debug_log "STEAM_COMPAT_CLIENT_INSTALL_PATH=$STEAM_COMPAT_CLIENT_INSTALL_PATH"
debug_log "STEAM_COMPAT_DATA_PATH=$STEAM_COMPAT_DATA_PATH"
debug_log "PROTON_EXEC=$PROTON_EXEC"
debug_log "Working directory: $(pwd)"
debug_log "Launch command: steam-run \"${PROTON_EXEC}\" run \"${APP_EXEC_FULL_PATH}\""

# Run the game
if ! steam-run "${PROTON_EXEC}" run "${APP_EXEC_FULL_PATH}" --skip-launcher; then
echo "Error: Failed to launch the game" >&2
gum spin --spinner dot --title "Launching game..." -- sleep 2
if ! steam-run "${PROTON_EXEC}" run "${APP_EXEC_FULL_PATH}"; then
gum style --foreground 1 "Error: Failed to launch the game"
exit 1
fi

0 comments on commit 8c464ea

Please sign in to comment.