Skip to content

Commit

Permalink
Add feature to find executable directory
Browse files Browse the repository at this point in the history
  • Loading branch information
R1kaB3rN committed Jul 4, 2024
1 parent 91c5f09 commit cf5ce86
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 0 deletions.
9 changes: 9 additions & 0 deletions umu/umu_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from umu_proton import get_umu_proton
from umu_runtime import setup_umu
from umu_util import (
find_subdir,
get_libc,
is_installed_verb,
is_winetricks_verb,
Expand Down Expand Up @@ -462,9 +463,17 @@ def run_command(command: list[AnyPath]) -> int:
# For winetricks, change directory to $PROTONPATH/protonfixes
if os.environ.get("EXE", "").endswith("winetricks"):
cwd = f"{os.environ['PROTONPATH']}/protonfixes"
elif os.environ.get("STORE") == "gog" and (
subdir := find_subdir(os.environ)
):
cwd = f"{os.environ['STEAM_COMPAT_INSTALL_PATH']}/{subdir}"
else:
# TODO: Create an environment variable to allow clients to not allow
# UMU to change directories so that the user's setting is respected.
cwd = Path.cwd()

log.debug("CWD: '%s'", cwd)

# Create a subprocess but do not set it as subreaper
# Unnecessary in a Flatpak and prctl() will fail if libc could not be found
if FLATPAK_PATH or not libc:
Expand Down
75 changes: 75 additions & 0 deletions umu/umu_util.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import os
from ctypes.util import find_library
from functools import lru_cache
from json import load
from pathlib import Path
from re import Pattern, compile
from shutil import which
from subprocess import PIPE, STDOUT, Popen, TimeoutExpired
from typing import Any

from umu_log import log

Expand Down Expand Up @@ -145,3 +148,75 @@ def is_steamdeck() -> bool:
break

return is_sd


def _parse_gogcfg(env: os._Environ[str]) -> Path | None:
json: dict[str, Any]
gog_info: Path
subdir: Path | None = None
install_dir: Path = Path(env["STEAM_COMPAT_INSTALL_PATH"])

if not install_dir.is_dir():
return None

try:
# Assume that there's only 1 *.info file in the game dir
gog_info = max(
file
for file in install_dir.glob("*.info")
if file.name.startswith("goggame")
)
except ValueError:
log.debug("No *.info files were found in '%s'", install_dir)
return None

with gog_info.open(mode="r", encoding="utf-8") as file:
json = load(file)

if not json:
log.debug("File '%s' is empty", gog_info)
log.debug("Will not change to a subdirectory")
return None

if "playTasks" not in json:
log.debug("File '%s' does not have a 'playTasks' property", gog_info)
log.debug("Will not change to a subdirectory")
return None

# Get the first result and assume it's the correct one
for item in json["playTasks"]:
if (path := item.get("path")) and len(
subpaths := Path(path).parts
) > 1:
subdir = Path(*subpaths[:-1])
log.debug(
"Found subdirectory '%s'",
subdir,
)
break

return subdir


def find_subdir(env: os._Environ[str]) -> Path | None:
"""Find the correct directory to run the executable by parsing a file.
Some games require to be executed in a specific way, by either requiring
the path to be relative or to be in a subdirectory within the game
directory. Otherwise, the game may fail to run. The correct subdirectory
is usually defined within a configuration file by the developer (e.g.,
installscript.vdf or *.info files).
"""
subdir: Path | None
store: str = env["STORE"]

# TODO: Parse Steam's .vdf files.
match store:
# For GOG, metadata is in *.info files
case "gog":
log.debug("GOG store detected")
subdir = _parse_gogcfg(env)
case _:
subdir = None

return subdir

0 comments on commit cf5ce86

Please sign in to comment.