Merge pull request #23 from R1kaB3rN/args

Change usage for Python rewrite
This commit is contained in:
Thomas Crider 2024-02-12 21:54:40 -07:00 committed by GitHub
commit 4f64389ec4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 1331 additions and 1649 deletions

File diff suppressed because it is too large Load Diff

108
ulwgl-run
View File

@ -1,108 +0,0 @@
#!/bin/sh
# use for debug only.
# set -x
if [ -z "$1" ] || [ -z "$WINEPREFIX" ] || [ -z "$GAMEID" ] || [ -z "$PROTONPATH" ]; then
echo "Usage: WINEPREFIX=<wine-prefix-path> GAMEID=<ulwgl-id> PROTONPATH=<proton-version-path> ./gamelauncher.sh <executable-path> <arguments>"
echo "Ex:"
echo "WINEPREFIX=$HOME/Games/epic-games-store GAMEID=egs PROTONPATH=\"$HOME/.steam/steam/compatibilitytools.d/GE-Proton8-28\" ./gamelauncher.sh \"$HOME/Games/epic-games-store/drive_c/Program Files (x86)/Epic Games/Launcher/Portal/Binaries/Win32/EpicGamesLauncher.exe\" \"-opengl -SkipBuildPatchPrereq\""
exit 1
fi
me="$(readlink -f "$0")"
here="${me%/*}"
if [ "$WINEPREFIX" ]; then
if [ ! -d "$WINEPREFIX" ]; then
mkdir -p "$WINEPREFIX"
export PROTON_DLL_COPY="*"
fi
if [ ! -d "$WINEPREFIX"/pfx ]; then
ln -s "$WINEPREFIX" "$WINEPREFIX"/pfx > /dev/null 2>&1
fi
if [ ! -f "$WINEPREFIX"/tracked_files ]; then
touch "$WINEPREFIX"/tracked_files
fi
if [ ! -f "$WINEPREFIX/dosdevices/" ]; then
mkdir -p "$WINEPREFIX"/dosdevices
ln -s "../drive_c" "$WINEPREFIX/dosdevices/c:" > /dev/null 2>&1
fi
fi
if [ -n "$PROTONPATH" ]; then
if [ ! -d "$PROTONPATH" ]; then
echo "ERROR: $PROTONPATH is invalid, aborting!"
exit 1
fi
fi
export ULWGL_ID="$GAMEID"
export STEAM_COMPAT_APP_ID="0"
numcheck='^[0-9]+$'
if echo "$ULWGL_ID" | cut -d "-" -f 2 | grep -Eq "$numcheck"; then
STEAM_COMPAT_APP_ID=$(echo "$ULWGL_ID" | cut -d "-" -f 2)
export STEAM_COMPAT_APP_ID
fi
export SteamAppId="$STEAM_COMPAT_APP_ID"
export SteamGameId="$STEAM_COMPAT_APP_ID"
# TODO: Ideally this should be the main game install path, which is often, but not always the path of the game's executable.
if [ -z "$STEAM_COMPAT_INSTALL_PATH" ]; then
exepath="$(readlink -f "$1")"
gameinstallpath="${exepath%/*}"
export STEAM_COMPAT_INSTALL_PATH="$gameinstallpath"
fi
compat_lib_path=$(findmnt -T "$STEAM_COMPAT_INSTALL_PATH" | tail -n 1 | awk '{ print $1 }')
if [ "$compat_lib_path" != "/" ]; then
export STEAM_COMPAT_LIBRARY_PATHS="${STEAM_COMPAT_LIBRARY_PATHS:+"${STEAM_COMPAT_LIBRARY_PATHS}:"}$compat_lib_path"
fi
if [ -z "$STEAM_RUNTIME_LIBRARY_PATH" ]; then
# The following info taken from steam ~/.local/share/ubuntu12_32/steam-runtime/run.sh
host_library_paths=
exit_status=0
ldconfig_output=$(/sbin/ldconfig -XNv 2> /dev/null; exit $?) || exit_status=$?
if [ $exit_status != 0 ]; then
echo "Warning: An unexpected error occurred while executing \"/sbin/ldconfig -XNv\", the exit status was $exit_status"
fi
while read -r line; do
# If line starts with a leading / and contains :, it's a new path prefix
case "$line" in /*:*)
library_path_prefix=$(echo "$line" | cut -d: -f1)
host_library_paths=$host_library_paths$library_path_prefix:
esac
done <<EOLDCONFIG
$ldconfig_output
EOLDCONFIG
host_library_paths="${LD_LIBRARY_PATH:+"${LD_LIBRARY_PATH}:"}$host_library_paths"
steam_runtime_library_paths="${STEAM_COMPAT_INSTALL_PATH}:${host_library_paths}"
export STEAM_RUNTIME_LIBRARY_PATH="$steam_runtime_library_paths"
fi
if [ -z "$PROTON_VERB" ]; then
export PROTON_VERB="waitforexitandrun"
fi
export STEAM_COMPAT_CLIENT_INSTALL_PATH=''
export STEAM_COMPAT_DATA_PATH="$WINEPREFIX"
export STEAM_COMPAT_SHADER_PATH="$STEAM_COMPAT_DATA_PATH"/shadercache
export PROTON_CRASH_REPORT_DIR='/tmp/ULWGL_crashreports'
export FONTCONFIG_PATH=''
export EXE="$1"
if [ "$EXE" = "createprefix" ]; then
# Hack, leave empty.
# forces proton to create a prefix without actually running anything.
EXE=""
fi
shift 1
export STEAM_COMPAT_TOOL_PATHS="$PROTONPATH:$here"
export STEAM_COMPAT_MOUNTS="$PROTONPATH:$here"
"$here"/ULWGL "--verb=$PROTON_VERB" -- "$PROTONPATH"/proton "$PROTON_VERB" "$EXE" "$@"

1
ulwgl-run Symbolic link
View File

@ -0,0 +1 @@
ulwgl_run.py

108
ulwgl-run-posix Executable file
View File

@ -0,0 +1,108 @@
#!/bin/sh
# use for debug only.
# set -x
if [ -z "$1" ] || [ -z "$WINEPREFIX" ] || [ -z "$GAMEID" ] || [ -z "$PROTONPATH" ]; then
echo "Usage: WINEPREFIX=<wine-prefix-path> GAMEID=<ulwgl-id> PROTONPATH=<proton-version-path> ./gamelauncher.sh <executable-path> <arguments>"
echo "Ex:"
echo "WINEPREFIX=$HOME/Games/epic-games-store GAMEID=egs PROTONPATH=\"$HOME/.steam/steam/compatibilitytools.d/GE-Proton8-28\" ./gamelauncher.sh \"$HOME/Games/epic-games-store/drive_c/Program Files (x86)/Epic Games/Launcher/Portal/Binaries/Win32/EpicGamesLauncher.exe\" \"-opengl -SkipBuildPatchPrereq\""
exit 1
fi
me="$(readlink -f "$0")"
here="${me%/*}"
if [ "$WINEPREFIX" ]; then
if [ ! -d "$WINEPREFIX" ]; then
mkdir -p "$WINEPREFIX"
export PROTON_DLL_COPY="*"
fi
if [ ! -d "$WINEPREFIX"/pfx ]; then
ln -s "$WINEPREFIX" "$WINEPREFIX"/pfx > /dev/null 2>&1
fi
if [ ! -f "$WINEPREFIX"/tracked_files ]; then
touch "$WINEPREFIX"/tracked_files
fi
if [ ! -f "$WINEPREFIX/dosdevices/" ]; then
mkdir -p "$WINEPREFIX"/dosdevices
ln -s "../drive_c" "$WINEPREFIX/dosdevices/c:" > /dev/null 2>&1
fi
fi
if [ -n "$PROTONPATH" ]; then
if [ ! -d "$PROTONPATH" ]; then
echo "ERROR: $PROTONPATH is invalid, aborting!"
exit 1
fi
fi
export ULWGL_ID="$GAMEID"
export STEAM_COMPAT_APP_ID="0"
numcheck='^[0-9]+$'
if echo "$ULWGL_ID" | cut -d "-" -f 2 | grep -Eq "$numcheck"; then
STEAM_COMPAT_APP_ID=$(echo "$ULWGL_ID" | cut -d "-" -f 2)
export STEAM_COMPAT_APP_ID
fi
export SteamAppId="$STEAM_COMPAT_APP_ID"
export SteamGameId="$STEAM_COMPAT_APP_ID"
# TODO: Ideally this should be the main game install path, which is often, but not always the path of the game's executable.
if [ -z "$STEAM_COMPAT_INSTALL_PATH" ]; then
exepath="$(readlink -f "$1")"
gameinstallpath="${exepath%/*}"
export STEAM_COMPAT_INSTALL_PATH="$gameinstallpath"
fi
compat_lib_path=$(findmnt -T "$STEAM_COMPAT_INSTALL_PATH" | tail -n 1 | awk '{ print $1 }')
if [ "$compat_lib_path" != "/" ]; then
export STEAM_COMPAT_LIBRARY_PATHS="${STEAM_COMPAT_LIBRARY_PATHS:+"${STEAM_COMPAT_LIBRARY_PATHS}:"}$compat_lib_path"
fi
if [ -z "$STEAM_RUNTIME_LIBRARY_PATH" ]; then
# The following info taken from steam ~/.local/share/ubuntu12_32/steam-runtime/run.sh
host_library_paths=
exit_status=0
ldconfig_output=$(/sbin/ldconfig -XNv 2> /dev/null; exit $?) || exit_status=$?
if [ $exit_status != 0 ]; then
echo "Warning: An unexpected error occurred while executing \"/sbin/ldconfig -XNv\", the exit status was $exit_status"
fi
while read -r line; do
# If line starts with a leading / and contains :, it's a new path prefix
case "$line" in /*:*)
library_path_prefix=$(echo "$line" | cut -d: -f1)
host_library_paths=$host_library_paths$library_path_prefix:
esac
done <<EOLDCONFIG
$ldconfig_output
EOLDCONFIG
host_library_paths="${LD_LIBRARY_PATH:+"${LD_LIBRARY_PATH}:"}$host_library_paths"
steam_runtime_library_paths="${STEAM_COMPAT_INSTALL_PATH}:${host_library_paths}"
export STEAM_RUNTIME_LIBRARY_PATH="$steam_runtime_library_paths"
fi
if [ -z "$PROTON_VERB" ]; then
export PROTON_VERB="waitforexitandrun"
fi
export STEAM_COMPAT_CLIENT_INSTALL_PATH=''
export STEAM_COMPAT_DATA_PATH="$WINEPREFIX"
export STEAM_COMPAT_SHADER_PATH="$STEAM_COMPAT_DATA_PATH"/shadercache
export PROTON_CRASH_REPORT_DIR='/tmp/ULWGL_crashreports'
export FONTCONFIG_PATH=''
export EXE="$1"
if [ "$EXE" = "createprefix" ]; then
# Hack, leave empty.
# forces proton to create a prefix without actually running anything.
EXE=""
fi
shift 1
export STEAM_COMPAT_TOOL_PATHS="$PROTONPATH:$here"
export STEAM_COMPAT_MOUNTS="$PROTONPATH:$here"
"$here"/ULWGL "--verb=$PROTON_VERB" -- "$PROTONPATH"/proton "$PROTON_VERB" "$EXE" "$@"

View File

@ -3,7 +3,7 @@ from pathlib import Path
from typing import Dict, Set from typing import Dict, Set
def enable_steam_game_drive(env: Dict[str, str]): def enable_steam_game_drive(env: Dict[str, str]) -> Dict[str, str]:
"""Enable Steam Game Drive functionality. """Enable Steam Game Drive functionality.
Expects STEAM_COMPAT_INSTALL_PATH to be set Expects STEAM_COMPAT_INSTALL_PATH to be set

View File

@ -2,83 +2,102 @@
import os import os
import argparse import argparse
from argparse import ArgumentParser, _ArgumentGroup, Namespace from argparse import ArgumentParser, Namespace
import sys import sys
from pathlib import Path from pathlib import Path
import tomllib import tomllib
from typing import Dict, Any, List, Set from typing import Dict, Any, List, Set, Union, Tuple
import gamelauncher_plugins import ulwgl_plugins
from re import match from re import match
# TODO: Only set the environment variables that are not empty
import subprocess import subprocess
def parse_args() -> Namespace: # noqa: D103 def parse_args() -> Union[Namespace, Tuple[str, List[str]]]: # noqa: D103
stores: List[str] = [ opt_args: Set[str] = {"--help", "-h", "--config"}
"amazon",
"battlenet",
"ea",
"egs",
"gog",
"humble",
"itchio",
"ubisoft",
]
exe: str = Path(__file__).name exe: str = Path(__file__).name
usage: str = """ usage: str = f"""
example usage: example usage:
{} --config example.toml WINEPREFIX= GAMEID= PROTONPATH= {exe} /home/foo/example.exe
{} --config /home/foo/example.toml --options '-opengl' WINEPREFIX= GAMEID= PROTONPATH= {exe} /home/foo/example.exe -opengl
WINEPREFIX= GAMEID= PROTONPATH= {} --exe /home/foo/example.exe --options '-opengl' WINEPREFIX= GAMEID= PROTONPATH= {exe} ""
WINEPREFIX= GAMEID= PROTONPATH= {} --exe /home/foo/example.exe --store gog WINEPREFIX= GAMEID= PROTONPATH= PROTON_VERB= {exe} /home/foo/example.exe
WINEPREFIX= GAMEID= PROTONPATH= {} --exe "" WINEPREFIX= GAMEID= PROTONPATH= STORE= {exe} /home/foo/example.exe
WINEPREFIX= GAMEID= PROTONPATH= {} --exe /home/foo/example.exe --verb waitforexitandrun {exe} --config /home/foo/example.toml
""".format(exe, exe, exe, exe, exe, exe) """
parser: ArgumentParser = argparse.ArgumentParser( parser: ArgumentParser = argparse.ArgumentParser(
description="Unified Linux Wine Game Launcher", description="Unified Linux Wine Game Launcher",
epilog=usage, epilog=usage,
formatter_class=argparse.RawTextHelpFormatter, formatter_class=argparse.RawTextHelpFormatter,
) )
group: _ArgumentGroup = parser.add_mutually_exclusive_group(required=True) parser.add_argument("--config", help="path to TOML file")
group.add_argument("--config", help="path to TOML file")
group.add_argument(
"--exe",
help="path to game executable\npass an empty string to create a prefix",
default=None,
)
parser.add_argument(
"--verb",
help="a verb to pass to Proton (default: waitforexitandrun)",
)
parser.add_argument(
"--options",
help="launch options for game executable\nNOTE: options must be wrapped in quotes",
)
parser.add_argument(
"--store",
help=f"the store of the game executable\nNOTE: will override the store specified in config\nexamples: {stores}",
)
return parser.parse_args(sys.argv[1:]) if not sys.argv[1:]:
err: str = "Please see project README.md for more info and examples.\nhttps://github.com/Open-Wine-Components/ULWGL-launcher"
parser.print_help()
raise SystemExit(err)
if sys.argv[1:][0] in opt_args:
return parser.parse_args(sys.argv[1:])
return (sys.argv[1], sys.argv[2:])
def _setup_pfx(path: str) -> None: def setup_pfx(path: str) -> None:
"""Create a symlink to the WINE prefix and tracked_files file.""" """Create a symlink to the WINE prefix and tracked_files file."""
if not (Path(path + "/pfx")).expanduser().is_symlink(): if not (Path(path + "/pfx")).expanduser().is_symlink():
# When creating the symlink, we want it to be in expanded form when passed unexpanded paths # When creating the symlink, we want it to be in expanded form when passed unexpanded paths
# Example: pfx -> /home/.wine # Example: pfx -> /home/foo/.wine
# NOTE: When parsing a config file, an error can be raised if the prefix doesn't already exist # NOTE: When parsing a config file, an error can be raised if the prefix doesn't already exist
Path(path + "/pfx").expanduser().symlink_to(Path(path).expanduser()) Path(path + "/pfx").expanduser().symlink_to(Path(path).expanduser())
Path(path + "/tracked_files").expanduser().touch() Path(path + "/tracked_files").expanduser().touch()
def check_env(env: Dict[str, str]) -> Dict[str, str]: def check_env(
env: Dict[str, str], toml: Dict[str, Any] = None
) -> Union[Dict[str, str], Dict[str, Any]]:
"""Before executing a game, check for environment variables and set them. """Before executing a game, check for environment variables and set them.
WINEPREFIX, GAMEID and PROTONPATH are strictly required. WINEPREFIX, GAMEID and PROTONPATH are strictly required.
""" """
if toml:
# Check for required or empty key/value pairs when reading a TOML config
# NOTE: Casing matters in the config and we don't check if the game id is set
table: str = "ulwgl"
required_keys: List[str] = ["proton", "prefix", "exe"]
if table not in toml:
err: str = f"Table '{table}' in TOML is not defined."
raise ValueError(err)
for key in required_keys:
if key not in toml[table]:
err: str = f"The following key in table '{table}' is required: {key}"
raise ValueError(err)
# Raise an error for executables that do not exist
# One case this can happen is when game options are appended at the end of the exe
# Users should use launch_args for that
if key == "exe" and not Path(toml[table][key]).expanduser().is_file():
val: str = toml[table][key]
err: str = f"Value for key '{key}' in TOML is not a file: {val}"
raise FileNotFoundError(err)
# The proton and wine prefix need to be folders
if (
key == "proton" and not Path(toml[table][key]).expanduser().is_dir()
) or (key == "prefix" and not Path(toml[table][key]).expanduser().is_dir()):
dir: str = Path(toml[table][key]).expanduser().as_posix()
err: str = f"Value for key '{key}' in TOML is not a directory: {dir}"
raise NotADirectoryError(err)
# Check for empty keys
for key, val in toml[table].items():
if not val and isinstance(val, str):
err: str = f"Value is empty for '{key}' in TOML.\nPlease specify a value or remove the following entry:\n{key} = {val}"
raise ValueError(err)
return toml
if "WINEPREFIX" not in os.environ: if "WINEPREFIX" not in os.environ:
err: str = "Environment variable not set or not a directory: WINEPREFIX" err: str = "Environment variable not set or not a directory: WINEPREFIX"
raise ValueError(err) raise ValueError(err)
@ -99,30 +118,68 @@ def check_env(env: Dict[str, str]) -> Dict[str, str]:
err: str = "Environment variable not set or not a directory: PROTONPATH" err: str = "Environment variable not set or not a directory: PROTONPATH"
raise ValueError(err) raise ValueError(err)
env["PROTONPATH"] = os.environ["PROTONPATH"] env["PROTONPATH"] = os.environ["PROTONPATH"]
env["STEAM_COMPAT_INSTALL_PATH"] = os.environ["PROTONPATH"]
return env return env
def set_env(env: Dict[str, str], args: Namespace) -> Dict[str, str]: def set_env(
env: Dict[str, str], args: Union[Namespace, Tuple[str, List[str]]]
) -> Dict[str, str]:
"""Set various environment variables for the Steam RT. """Set various environment variables for the Steam RT.
Expects to be invoked if not reading a TOML file Filesystem paths will be formatted and expanded as POSIX
""" """
_setup_pfx(env["WINEPREFIX"]) verbs: Set[str] = {
is_create_prefix: bool = False "waitforexitandrun",
"run",
"runinprefix",
"destroyprefix",
"getcompatpath",
"getnativepath",
}
if not getattr(args, "exe", None): # PROTON_VERB
is_create_prefix = True # For invalid Proton verbs, just assign the waitforexitandrun
if "PROTON_VERB" in os.environ and os.environ["PROTON_VERB"] in verbs:
env["PROTON_VERB"] = os.environ["PROTON_VERB"]
else:
env["PROTON_VERB"] = "waitforexitandrun"
# Sets the environment variables: EXE # EXE
for arg, val in vars(args).items(): # Empty string for EXE will be used to create a prefix
if arg == "exe" and not is_create_prefix: if isinstance(args, tuple) and isinstance(args[0], str) and not args[0]:
# NOTE: options can possibly be appended at the end env["EXE"] = ""
env["EXE"] = val env["STEAM_COMPAT_INSTALL_PATH"] = ""
elif arg == "options" and val and not is_create_prefix: env["PROTON_VERB"] = "waitforexitandrun"
# NOTE: assume it's space separated elif isinstance(args, tuple):
env["EXE"] = env["EXE"] + " " + " ".join(val.split(" ")) env["EXE"] = Path(args[0]).expanduser().as_posix()
env["STEAM_COMPAT_INSTALL_PATH"] = Path(env["EXE"]).parent.as_posix()
else:
# Config branch
env["EXE"] = Path(env["EXE"]).expanduser().as_posix()
env["STEAM_COMPAT_INSTALL_PATH"] = Path(env["EXE"]).parent.as_posix()
if "STORE" in os.environ:
env["STORE"] = os.environ["STORE"]
# ULWGL_ID
env["ULWGL_ID"] = env["GAMEID"]
env["STEAM_COMPAT_APP_ID"] = "0"
if match(r"^ulwgl-[\d\w]+$", env["ULWGL_ID"]):
env["STEAM_COMPAT_APP_ID"] = env["ULWGL_ID"][env["ULWGL_ID"].find("-") + 1 :]
env["SteamAppId"] = env["STEAM_COMPAT_APP_ID"]
env["SteamGameId"] = env["SteamAppId"]
# PATHS
env["WINEPREFIX"] = Path(env["WINEPREFIX"]).expanduser().as_posix()
env["PROTONPATH"] = Path(env["PROTONPATH"]).expanduser().as_posix()
env["STEAM_COMPAT_DATA_PATH"] = env["WINEPREFIX"]
env["STEAM_COMPAT_SHADER_PATH"] = env["STEAM_COMPAT_DATA_PATH"] + "/shadercache"
env["STEAM_COMPAT_TOOL_PATHS"] = (
env["PROTONPATH"] + ":" + Path(__file__).parent.as_posix()
)
env["STEAM_COMPAT_MOUNTS"] = env["STEAM_COMPAT_TOOL_PATHS"]
return env return env
@ -149,62 +206,35 @@ def set_env_toml(env: Dict[str, str], args: Namespace) -> Dict[str, str]:
with Path(path_config).open(mode="rb") as file: with Path(path_config).open(mode="rb") as file:
toml = tomllib.load(file) toml = tomllib.load(file)
if not ( check_env(env, toml)
Path(toml["ulwgl"]["prefix"]).expanduser().is_dir()
or Path(toml["ulwgl"]["proton"]).expanduser().is_dir()
):
err: str = "Value for 'prefix' or 'proton' in TOML is not a directory."
raise NotADirectoryError(err)
# Set the values read from TOML to environment variables
# If necessary, raise an error on invalid inputs
for key, val in toml["ulwgl"].items(): for key, val in toml["ulwgl"].items():
# Handle cases for empty values
if not val and isinstance(val, str):
err: str = f'Value is empty for key in TOML: {key}\nPlease specify a value or remove the following entry:\n{key} = "{val}"'
raise ValueError(err)
if key == "prefix": if key == "prefix":
env["WINEPREFIX"] = val env["WINEPREFIX"] = val
_setup_pfx(val)
elif key == "game_id": elif key == "game_id":
env["GAMEID"] = val env["GAMEID"] = val
elif key == "proton": elif key == "proton":
env["PROTONPATH"] = val env["PROTONPATH"] = val
env["STEAM_COMPAT_INSTALL_PATH"] = val
elif key == "store": elif key == "store":
env["STORE"] = val env["STORE"] = val
elif key == "exe": elif key == "exe":
# Raise an error for executables that do not exist
# One case this can happen is when game options are appended at the end of the exe
if not Path(val).expanduser().is_file():
err: str = "Value for key 'exe' in TOML is not a file."
raise FileNotFoundError(err)
# It's possible for users to pass values to --options
# Add any if they exist
if toml.get("ulwgl").get("launch_args"): if toml.get("ulwgl").get("launch_args"):
env["EXE"] = val + " " + " ".join(toml.get("ulwgl").get("launch_args")) env["EXE"] = val + " " + " ".join(toml.get("ulwgl").get("launch_args"))
else: else:
env["EXE"] = val env["EXE"] = val
if getattr(args, "options", None):
# Assume space separated options and just trust it
env["EXE"] = (
env["EXE"]
+ " "
+ " ".join(getattr(args, "options", None).split(" "))
)
return env return env
def build_command(env: Dict[str, str], command: List[str], verb: str) -> List[str]: def build_command(
env: Dict[str, str], command: List[str], opts: List[str] = None
) -> List[str]:
"""Build the command to be executed.""" """Build the command to be executed."""
paths: List[Path] = [ paths: List[Path] = [
Path(Path().home().as_posix() + "/.local/share/ULWGL/ULWGL"), Path(Path().home().as_posix() + "/.local/share/ULWGL/ULWGL"),
Path(Path(__file__).cwd().as_posix() + "/ULWGL"), Path(Path(__file__).cwd().as_posix() + "/ULWGL"),
] ]
entry_point: str = "" entry_point: str = ""
verb: str = env["PROTON_VERB"]
# Find the ULWGL script in $HOME/.local/share then cwd # Find the ULWGL script in $HOME/.local/share then cwd
for path in paths: for path in paths:
@ -230,6 +260,9 @@ def build_command(env: Dict[str, str], command: List[str], verb: str) -> List[st
[Path(env.get("PROTONPATH") + "/proton").as_posix(), verb, env.get("EXE")] [Path(env.get("PROTONPATH") + "/proton").as_posix(), verb, env.get("EXE")]
) )
if opts:
command.extend([*opts])
return command return command
@ -253,68 +286,32 @@ def main() -> None: # noqa: D103
"SteamGameId": "", "SteamGameId": "",
"STEAM_RUNTIME_LIBRARY_PATH": "", "STEAM_RUNTIME_LIBRARY_PATH": "",
"STORE": "", "STORE": "",
"PROTON_VERB": "",
"ULWGL_ID": "",
} }
command: List[str] = [] command: List[str] = []
verb: str = "waitforexitandrun" args: Union[Namespace, Tuple[str, List[str]]] = parse_args()
# Represents a valid list of current supported Proton verbs opts: List[str] = None
verbs: Set[str] = {
"waitforexitandrun",
"run",
"runinprefix",
"destroyprefix",
"getcompatpath",
"getnativepath",
}
args: Namespace = parse_args()
if getattr(args, "config", None): if isinstance(args, Namespace):
set_env_toml(env, args) set_env_toml(env, args)
else: else:
# Reference the game options
opts = args[1]
check_env(env) check_env(env)
set_env(env, args)
if getattr(args, "verb", None) and getattr(args, "verb", None) in verbs: setup_pfx(env["WINEPREFIX"])
verb = getattr(args, "verb", None) set_env(env, args)
if getattr(args, "store", None): # Game Drive
env["STORE"] = getattr(args, "store", None) ulwgl_plugins.enable_steam_game_drive(env)
env["ULWGL_ID"] = env["GAMEID"] # Set all environment variables
env["STEAM_COMPAT_APP_ID"] = "0"
if match(r"^ulwgl-[\d\w]+$", env["ULWGL_ID"]):
env["STEAM_COMPAT_APP_ID"] = env["ULWGL_ID"][env["ULWGL_ID"].find("-") + 1 :]
env["SteamAppId"] = env["STEAM_COMPAT_APP_ID"]
env["SteamGameId"] = env["SteamAppId"]
env["WINEPREFIX"] = Path(env["WINEPREFIX"]).expanduser().as_posix()
env["PROTONPATH"] = Path(env["PROTONPATH"]).expanduser().as_posix()
env["STEAM_COMPAT_DATA_PATH"] = env["WINEPREFIX"]
env["STEAM_COMPAT_SHADER_PATH"] = env["STEAM_COMPAT_DATA_PATH"] + "/shadercache"
env["STEAM_COMPAT_INSTALL_PATH"] = Path(env["EXE"]).parent.expanduser().as_posix()
env["EXE"] = Path(env["EXE"]).expanduser().as_posix()
env["STEAM_COMPAT_TOOL_PATHS"] = (
env["PROTONPATH"] + ":" + Path(__file__).parent.as_posix()
)
env["STEAM_COMPAT_MOUNTS"] = env["STEAM_COMPAT_TOOL_PATHS"]
# Create an empty Proton prefix when asked
if not getattr(args, "exe", None) and not getattr(args, "config", None):
env["EXE"] = ""
env["STEAM_COMPAT_INSTALL_PATH"] = ""
verb = "waitforexitandrun"
# Game Drive functionality
gamelauncher_plugins.enable_steam_game_drive(env)
# Set all environment variable
# NOTE: `env` after this block should be read only # NOTE: `env` after this block should be read only
for key, val in env.items(): for key, val in env.items():
print(f"Setting environment variable: {key}={val}")
os.environ[key] = val os.environ[key] = val
build_command(env, command, verb) build_command(env, command, opts)
print(f"The following command will be executed: {command}")
subprocess.run(command, check=True, stdout=subprocess.PIPE, text=True) subprocess.run(command, check=True, stdout=subprocess.PIPE, text=True)

1080
ulwgl_test.py Normal file

File diff suppressed because it is too large Load Diff