1
0
Fork 0
mirror of synced 2024-06-02 10:44:40 +12:00
Rare/rare/shared/workers/wine_resolver.py

173 lines
7.1 KiB
Python
Raw Normal View History

import os
import platform
import time
from configparser import ConfigParser
from logging import getLogger
2024-02-13 05:30:23 +13:00
from typing import Union, Iterable, List, Tuple, Dict
2024-02-13 05:30:23 +13:00
from PyQt5.QtCore import pyqtSignal, QObject
from rare.lgndr.core import LegendaryCore
from rare.models.game import RareGame
from rare.models.pathspec import PathSpec
2024-02-13 05:30:23 +13:00
from rare.shared.wrappers import Wrappers
from rare.utils import config_helper as config
from rare.utils.misc import path_size, format_size
from .worker import Worker
if platform.system() == "Windows":
# noinspection PyUnresolvedReferences
import winreg # pylint: disable=E0401
from legendary.lfs import windows_helpers
else:
2024-02-18 23:44:04 +13:00
from rare.utils.compat import utils as compat_utils, steam
logger = getLogger("WineResolver")
class WinePathResolver(Worker):
class Signals(QObject):
result_ready = pyqtSignal(str, str)
2024-02-13 05:30:23 +13:00
def __init__(self, core: LegendaryCore, app_name: str, path: str):
super(WinePathResolver, self). __init__()
self.signals = WinePathResolver.Signals()
2024-02-13 05:30:23 +13:00
self.core = core
self.app_name = app_name
self.path = path
2024-02-13 05:30:23 +13:00
@staticmethod
def _configure_process(core: LegendaryCore, app_name: str) -> Tuple[List, Dict]:
2024-02-18 23:44:04 +13:00
tool: steam.CompatibilityTool = None
2024-02-13 05:30:23 +13:00
if config.get_boolean(app_name, "no_wine"):
wrappers = Wrappers()
for w in wrappers.get_game_wrapper_list(app_name):
if w.is_compat_tool:
2024-02-18 23:44:04 +13:00
for t in steam.find_tools():
2024-02-13 05:30:23 +13:00
if t.checksum == w.checksum:
tool = t
break
cmd = core.get_app_launch_command(
app_name,
2024-02-18 23:44:04 +13:00
wrapper=tool.as_str(steam.SteamVerb.RUN_IN_PREFIX) if tool is not None else None,
2024-02-13 05:30:23 +13:00
disable_wine=config.get_boolean(app_name, "no_wine")
)
env = core.get_app_environment(app_name, disable_wine=config.get_boolean(app_name, "no_wine"))
env = compat_utils.get_host_environment(env, silent=True)
return cmd, env
@staticmethod
def _resolve_unix_path(cmd, env, path: str) -> str:
logger.info("Resolving path '%s'", path)
2024-02-13 05:30:23 +13:00
wine_path = compat_utils.resolve_path(cmd, env, path)
logger.info("Resolved Wine path '%s'", wine_path)
unix_path = compat_utils.convert_to_unix_path(cmd, env, wine_path)
logger.info("Resolved Unix path '%s'", unix_path)
return unix_path
def run_real(self):
2024-02-13 05:30:23 +13:00
command, environ = self._configure_process(self.core, self.app_name)
if not (command and environ):
logger.error("Cannot setup %s, missing infomation", {type(self).__name__})
self.signals.result_ready.emit("", self.app_name)
path = self._resolve_unix_path(command, environ, self.path)
self.signals.result_ready.emit(path, self.app_name)
return
class WineSavePathResolver(WinePathResolver):
def __init__(self, core: LegendaryCore, rgame: RareGame):
path = PathSpec(core, rgame.igame).resolve_egl_path_vars(rgame.raw_save_path)
2024-02-13 05:30:23 +13:00
super(WineSavePathResolver, self).__init__(rgame.core, rgame.app_name, str(path))
self.rgame = rgame
def run_real(self):
logger.info("Resolving save path for %s (%s)", self.rgame.app_title, self.rgame.app_name)
2024-02-13 05:30:23 +13:00
command, environ = self._configure_process(self.core, self.rgame.app_name)
if not (command and environ):
logger.error("Cannot setup %s, missing infomation", {type(self).__name__})
self.signals.result_ready.emit("", self.rgame.app_name)
path = self._resolve_unix_path(command, environ, self.path)
# Clean wine output
# pylint: disable=E1136
if os.path.exists(path):
self.rgame.save_path = path
self.signals.result_ready.emit(path, self.rgame.app_name)
return
2024-02-13 05:30:23 +13:00
class OriginWineWorker(WinePathResolver):
def __init__(self, core: LegendaryCore, games: Union[Iterable[RareGame], RareGame]):
2024-02-13 05:30:23 +13:00
super(OriginWineWorker, self).__init__(core, "", "")
self.__cache: dict[str, ConfigParser] = {}
self.core = core
self.games = [games] if isinstance(games, RareGame) else games
2024-02-13 05:30:23 +13:00
def run_real(self) -> None:
t = time.time()
for rgame in self.games:
reg_path: str = rgame.game.metadata \
.get("customAttributes", {}) \
.get("RegistryPath", {}).get("value", None)
if not reg_path:
continue
reg_key: str = rgame.game.metadata \
.get("customAttributes", {}) \
.get("RegistryKey", {}).get("value", None)
if not reg_key:
continue
if platform.system() == "Windows":
install_dir = windows_helpers.query_registry_value(winreg.HKEY_LOCAL_MACHINE, reg_path, reg_key)
else:
2024-02-13 05:30:23 +13:00
command, environ = self._configure_process(self.core, rgame.app_name)
prefix = config.get_prefix(rgame.app_name)
if not prefix:
return
2024-02-13 05:30:23 +13:00
use_wine = True
if not use_wine:
2023-12-08 21:46:07 +13:00
# lk: this is the original way of getting the path by parsing "system.reg"
2024-02-13 05:30:23 +13:00
reg = self.__cache.get(prefix, None) or compat_utils.read_registry("system.reg", prefix)
self.__cache[prefix] = reg
reg_path = reg_path.replace("SOFTWARE", "Software").replace("WOW6432Node", "Wow6432Node")
# lk: split and rejoin the registry path to avoid slash expansion
reg_path = "\\\\".join([x for x in reg_path.split("\\") if bool(x)])
install_dir = reg.get(reg_path, f'"{reg_key}"', fallback=None)
else:
# lk: this is the alternative way of getting the path by using wine itself
2024-02-13 05:30:23 +13:00
install_dir = compat_utils.query_reg_key(command, environ, f"HKLM\\{reg_path}", reg_key)
if install_dir:
2023-09-03 23:47:44 +12:00
logger.debug("Found Wine install directory %s", install_dir)
2024-02-13 05:30:23 +13:00
install_dir = compat_utils.convert_to_unix_path(command, environ, install_dir)
2023-09-03 23:47:44 +12:00
if install_dir:
logger.debug("Found Unix install directory %s", install_dir)
else:
logger.info("Could not find Unix install directory for %s", rgame.app_title)
2023-09-03 23:47:44 +12:00
else:
logger.info("Could not find Wine install directory for %s", rgame.app_title)
if install_dir:
if os.path.isdir(install_dir):
install_size = path_size(install_dir)
rgame.set_origin_attributes(install_dir, install_size)
logger.info("Origin game %s (%s, %s)", rgame.app_title, install_dir, format_size(install_size))
else:
logger.warning("Origin game %s (%s does not exist)", rgame.app_title, install_dir)
2023-09-03 23:47:44 +12:00
else:
logger.info("Origin game %s is not installed", rgame.app_title)
2023-09-03 23:47:44 +12:00
logger.info("Origin worker finished in %ss", time.time() - t)