Add proton module

This commit is contained in:
Mathieu Comandon 2024-02-27 15:53:36 -08:00
parent 4c002148c3
commit 16df7887a4
6 changed files with 76 additions and 64 deletions

View file

@ -1,6 +1,6 @@
import re
from itertools import repeat
from collections import defaultdict
from itertools import repeat
from lutris import settings
from lutris.database import sql

View file

@ -2,7 +2,6 @@
# pylint: disable=too-many-arguments
import os
import shlex
import subprocess
import time
from lutris import runtime, settings
@ -12,6 +11,7 @@ from lutris.util import linux, system
from lutris.util.log import logger
from lutris.util.shell import get_shell_command
from lutris.util.strings import split_arguments
from lutris.util.wine import proton
from lutris.util.wine.cabinstall import CabInstaller
from lutris.util.wine.prefix import WinePrefixManager
from lutris.util.wine.wine import (
@ -138,7 +138,7 @@ def create_prefix( # noqa: C901
wineenv["WINE_SKIP_MONO_INSTALLATION"] = "1"
overrides["mscoree"] = "disabled"
if ("Proton" not in wine_path) or ("lutris" in wine_path and "Proton" in wine_path):
if not proton.is_proton_path(wine_path):
system.execute([wineboot_path], env=wineenv)
for loop_index in range(1000):
time.sleep(0.5)
@ -153,8 +153,7 @@ def create_prefix( # noqa: C901
# TODO: Determine and insert GAMEID and STORE
wineenv["GAMEID"] = "ulwgl-foo" # Wrong
wineenv["PROTONPATH"] = settings.RUNNER_DIR # Wrong, optional
ulwgl_path = system.find_executable("ulwgl-run")
system.execute([ulwgl_path, "createprefix"], env=wineenv)
system.execute([proton.get_ulwgl_path(), "createprefix"], env=wineenv)
logger.info("%s Prefix created in %s", arch, prefix)
prefix_manager = WinePrefixManager(prefix)
@ -315,17 +314,19 @@ def wineexec( # noqa: C901
if overrides:
wineenv["WINEDLLOVERRIDES"] = get_overrides_env(overrides)
if "Proton" in wine_path: # wrong condition, catches lutris-GE-Proton
if proton.is_proton_path(wine_path):
# TODO: Determine and insert GAMEID and STORE
wineenv["GAMEID"] = "ulwgl-foo" # wrong, this value should never be used.
wineenv["PROTONPATH"] = os.path.abspath(os.path.join(os.path.dirname(wine_path), "../../")) # wrong, proton path is optional
wineenv["PROTONPATH"] = os.path.abspath(
os.path.join(os.path.dirname(wine_path), "../../")
) # wrong, proton path is optional
baseenv = runner.get_env(disable_runtime=disable_runtime)
baseenv.update(wineenv)
baseenv.update(env)
if "Proton" in wine_path: # wrong condition, protonpath optional
wine_path = system.find_executable("ulwgl-run") # wrong, should be checked before
wine_path = proton.get_ulwgl_path() # wrong, should be checked before
command_parameters = [wine_path]
if executable:

View file

@ -2,7 +2,6 @@
# pylint: disable=too-many-lines
import os
import shlex
import subprocess
from gettext import gettext as _
from typing import Dict, Tuple
@ -40,6 +39,7 @@ from lutris.util.graphics import drivers, vkquery
from lutris.util.linux import LINUX_SYSTEM
from lutris.util.log import logger
from lutris.util.strings import split_arguments
from lutris.util.wine import proton
from lutris.util.wine.d3d_extras import D3DExtrasManager
from lutris.util.wine.dgvoodoo2 import dgvoodoo2Manager
from lutris.util.wine.dxvk import REQUIRED_VULKAN_API_VERSION, DXVKManager
@ -56,7 +56,6 @@ from lutris.util.wine.wine import (
get_default_wine_version,
get_installed_wine_versions,
get_overrides_env,
get_proton_paths,
get_real_executable,
get_system_wine_version,
get_wine_path_for_version,
@ -1076,7 +1075,7 @@ class wine(Runner):
env["WINE_GECKO_CACHE_DIR"] = os.path.join(WINE_DIR, wine_config_version, "gecko")
# We don't want to override gstreamer for proton, it has it's own version
if ("Proton" not in WINE_DIR) or ("lutris" in WINE_DIR and "Proton" in WINE_DIR):
if not proton.is_proton_path(WINE_DIR):
if is_gstreamer_build(wine_exe):
path_64 = os.path.join(WINE_DIR, wine_config_version, "lib64/gstreamer-1.0/")
path_32 = os.path.join(WINE_DIR, wine_config_version, "lib/gstreamer-1.0/")
@ -1114,9 +1113,7 @@ class wine(Runner):
env["WINEDLLOVERRIDES"] = get_overrides_env(self.dll_overrides)
if (
wine_config_version and "Proton" in wine_config_version and "lutris" not in wine_config_version
): # duplicated code
if proton.is_proton_path(wine_config_version):
if "GAMEID" not in env:
env["GAMEID"] = "ULWGL-foo" # wrong value, needs to be fixed
# In stable versions of proton this can be dist/bin insteasd of files/bin
@ -1133,7 +1130,7 @@ class wine(Runner):
exe = self.get_executable()
if WINE_DIR:
wine_path = os.path.dirname(os.path.dirname(exe))
for proton_path in get_proton_paths():
for proton_path in proton.get_proton_paths():
if proton_path in exe:
wine_path = os.path.dirname(os.path.dirname(exe))
except MisconfigurationError:

View file

@ -226,6 +226,7 @@ def find_executable(exec_name: str) -> str:
exe = shutil.which(exec_name)
if exe:
return exe
raise MissingExecutableError(_("The executable '%s' could not be found.") % exec_name)
def get_pid(program, multiple=False):

View file

@ -0,0 +1,58 @@
"""Utility module to deal with Proton and ULWGL"""
import os
from typing import Generator, List
from lutris.util import system
from lutris.util.steam.config import get_steamapps_dirs
def is_proton_path(wine_path):
return "Proton" in wine_path and "lutris" not in wine_path
def get_ulwgl_path():
return system.find_executable("ulwgl-run")
def _iter_proton_locations() -> Generator[str, None, None]:
"""Iterate through all existing Proton locations"""
try:
steamapp_dirs = get_steamapps_dirs()
except:
return # in case of corrupt or unreadable Steam configuration files!
for path in [os.path.join(p, "common") for p in steamapp_dirs]:
if os.path.isdir(path):
yield path
for path in [os.path.join(p, "") for p in steamapp_dirs]:
if os.path.isdir(path):
yield path
def get_proton_paths() -> List[str]:
"""Get the Folder that contains all the Proton versions. Can probably be improved"""
paths = set()
for path in _iter_proton_locations():
proton_versions = [p for p in os.listdir(path) if "Proton" in p]
for version in proton_versions:
if system.path_exists(os.path.join(path, version, "dist/bin/wine")):
paths.add(path)
if system.path_exists(os.path.join(path, version, "files/bin/wine")):
paths.add(path)
return list(paths)
def list_proton_versions() -> List[str]:
"""Return the list of Proton versions installed in Steam"""
versions = []
for proton_path in get_proton_paths():
proton_versions = [p for p in os.listdir(proton_path) if "Proton" in p]
for version in proton_versions:
path = os.path.join(proton_path, version, "dist/bin/wine")
if os.path.isfile(path):
versions.append(version)
# Support Proton Experimental
path = os.path.join(proton_path, version, "files/bin/wine")
if os.path.isfile(path):
versions.append(version)
return versions

View file

@ -2,16 +2,15 @@
import os
from collections import OrderedDict
from gettext import gettext as _
from typing import Dict, Generator, List, Tuple
from typing import Dict, List, Tuple
from lutris import settings
from lutris.api import get_default_wine_runner_version_info
from lutris.exceptions import MisconfigurationError, UnavailableRunnerError, UnspecifiedVersionError
from lutris.util import cache_single, linux, system
from lutris.util.log import logger
from lutris.util.steam.config import get_steamapps_dirs
from lutris.util.strings import parse_version
from lutris.util.wine import fsync
from lutris.util.wine import fsync, proton
WINE_DIR: str = os.path.join(settings.RUNNER_DIR, "wine")
WINE_DEFAULT_ARCH: str = "win64" if linux.LINUX_SYSTEM.is_64_bit else "win32"
@ -35,34 +34,6 @@ except Exception as ex:
logger.exception("Unable to enumerate system Wine versions: %s", ex)
def _iter_proton_locations() -> Generator[str, None, None]:
"""Iterate through all existing Proton locations"""
try:
steamapp_dirs = get_steamapps_dirs()
except:
return # in case of corrupt or unreadable Steam configuration files!
for path in [os.path.join(p, "common") for p in steamapp_dirs]:
if os.path.isdir(path):
yield path
for path in [os.path.join(p, "") for p in steamapp_dirs]:
if os.path.isdir(path):
yield path
def get_proton_paths() -> List[str]:
"""Get the Folder that contains all the Proton versions. Can probably be improved"""
paths = set()
for path in _iter_proton_locations():
proton_versions = [p for p in os.listdir(path) if "Proton" in p]
for version in proton_versions:
if system.path_exists(os.path.join(path, version, "dist/bin/wine")):
paths.add(path)
if system.path_exists(os.path.join(path, version, "files/bin/wine")):
paths.add(path)
return list(paths)
def detect_arch(prefix_path: str = None, wine_path: str = None) -> str:
"""Given a Wine prefix path, return its architecture"""
if prefix_path and is_prefix_directory(prefix_path):
@ -149,26 +120,10 @@ def list_lutris_wine_versions() -> List[str]:
return versions
def list_proton_versions() -> List[str]:
"""Return the list of Proton versions installed in Steam"""
versions = []
for proton_path in get_proton_paths():
proton_versions = [p for p in os.listdir(proton_path) if "Proton" in p]
for version in proton_versions:
path = os.path.join(proton_path, version, "dist/bin/wine")
if os.path.isfile(path):
versions.append(version)
# Support Proton Experimental
path = os.path.join(proton_path, version, "files/bin/wine")
if os.path.isfile(path):
versions.append(version)
return versions
@cache_single
def get_installed_wine_versions() -> List[str]:
"""Return the list of Wine versions installed"""
return list_system_wine_versions() + list_lutris_wine_versions() + list_proton_versions()
return list_system_wine_versions() + list_lutris_wine_versions() + proton.list_proton_versions()
def get_wine_path_for_version(version: str, config: dict = None) -> str:
@ -183,7 +138,7 @@ def get_wine_path_for_version(version: str, config: dict = None) -> str:
if version in WINE_PATHS:
return system.find_executable(WINE_PATHS[version])
if "Proton" in version:
for proton_path in get_proton_paths():
for proton_path in proton.get_proton_paths():
if os.path.isfile(os.path.join(proton_path, version, "dist/bin/wine")):
return os.path.join(proton_path, version, "dist/bin/wine")
if os.path.isfile(os.path.join(proton_path, version, "files/bin/wine")):