From 92346e11d0a50aabd840dcab0566cc6bea3652d8 Mon Sep 17 00:00:00 2001 From: loathingKernel <142770+loathingKernel@users.noreply.github.com> Date: Tue, 7 Mar 2023 22:53:18 +0200 Subject: [PATCH] OriginWineWorker: Execute during launch and properly resolve paths for Wine --- rare/components/tabs/games/__init__.py | 6 +- .../tabs/games/game_info/game_info.py | 2 +- rare/shared/rare_core.py | 14 +++++ rare/shared/workers/__init__.py | 1 + rare/shared/workers/fetch.py | 1 + rare/shared/workers/wine_resolver.py | 60 +++++++++++++------ 6 files changed, 60 insertions(+), 24 deletions(-) diff --git a/rare/components/tabs/games/__init__.py b/rare/components/tabs/games/__init__.py index c5ac8aa2..25fd575b 100644 --- a/rare/components/tabs/games/__init__.py +++ b/rare/components/tabs/games/__init__.py @@ -1,6 +1,6 @@ from logging import getLogger -from PyQt5.QtCore import QSettings, Qt, pyqtSlot, QThreadPool +from PyQt5.QtCore import QSettings, Qt, pyqtSlot from PyQt5.QtWidgets import QStackedWidget, QVBoxLayout, QWidget, QScrollArea, QFrame from rare.models.game import RareGame @@ -11,7 +11,6 @@ from rare.shared import ( ImageManagerSingleton, ) from rare.shared import RareCore -from rare.shared.workers.wine_resolver import OriginWineWorker from rare.widgets.library_layout import LibraryLayout from rare.widgets.sliding_stack import SlidingStackedWidget from .game_info import GameInfoTabs @@ -155,9 +154,6 @@ class GamesTab(QStackedWidget): self.filter_games(self.active_filter) self.update_count_games_label() - worker = OriginWineWorker(self.core, self.rcore.origin_games) - QThreadPool.globalInstance().start(worker) - def add_library_widget(self, rgame: RareGame): try: icon_widget, list_widget = self.library_controller.add_game(rgame) diff --git a/rare/components/tabs/games/game_info/game_info.py b/rare/components/tabs/games/game_info/game_info.py index 079b67ab..19763b39 100644 --- a/rare/components/tabs/games/game_info/game_info.py +++ b/rare/components/tabs/games/game_info/game_info.py @@ -248,7 +248,7 @@ class GameInfo(QWidget, SideTabContents): self.ui.lbl_install_size.setEnabled(bool(self.rgame.install_size)) self.ui.install_size.setEnabled(bool(self.rgame.install_size)) self.ui.install_size.setText( - format_size(self.rgame.igame.install_size) if self.rgame.install_size else "N/A" + format_size(self.rgame.install_size) if self.rgame.install_size else "N/A" ) self.ui.lbl_install_path.setEnabled(bool(self.rgame.install_path)) diff --git a/rare/shared/rare_core.py b/rare/shared/rare_core.py index 79235c6f..53b85f03 100644 --- a/rare/shared/rare_core.py +++ b/rare/shared/rare_core.py @@ -21,6 +21,7 @@ from .workers import ( FetchWorker, GamesWorker, NonAssetWorker, + OriginWineWorker, SavesWorker, EntitlementsWorker, ) @@ -48,6 +49,7 @@ class RareCore(QObject): self.__games_fetched: bool = False self.__non_asset_fetched: bool = False + self.__origin_resolved: bool = False self.__saves_fetched: bool = False self.__entitlements_fetched: bool = False @@ -276,6 +278,9 @@ class RareCore(QObject): self.__add_games_and_dlcs(games, dlc_dict) self.__non_asset_fetched = True status = "Loaded games without assets" + if res_type == FetchWorker.Result.ORIGIN: + self.__origin_resolved = True + status = "Resolved Origin installation status" if res_type == FetchWorker.Result.SAVES: saves, _ = result for save in saves: @@ -291,6 +296,7 @@ class RareCore(QObject): fetched = [ self.__games_fetched, self.__non_asset_fetched, + self.__origin_resolved, self.__saves_fetched, self.__entitlements_fetched, ] @@ -307,6 +313,7 @@ class RareCore(QObject): def fetch(self): self.__games_fetched: bool = False self.__non_asset_fetched: bool = False + self.__origin_resolved: bool = False self.__saves_fetched: bool = False self.__entitlements_fetched: bool = False @@ -325,9 +332,16 @@ class RareCore(QObject): else: self.__saves_fetched = True + def resolve_origin(self): + origin_worker = OriginWineWorker(self.__core, self.__args, self.origin_games) + origin_worker.signals.result.connect(self.handle_result) + QThreadPool.globalInstance().start(origin_worker) + + def fetch_extra(self): non_asset_worker = NonAssetWorker(self.__core, self.__args) non_asset_worker.signals.result.connect(self.handle_result) + non_asset_worker.signals.finished.connect(self.resolve_origin) QThreadPool.globalInstance().start(non_asset_worker) entitlements_worker = EntitlementsWorker(self.__core, self.__args) diff --git a/rare/shared/workers/__init__.py b/rare/shared/workers/__init__.py index 5defd286..3beeab9e 100644 --- a/rare/shared/workers/__init__.py +++ b/rare/shared/workers/__init__.py @@ -3,4 +3,5 @@ from .install_info import InstallInfoWorker from .move import MoveWorker from .uninstall import UninstallWorker from .verify import VerifyWorker +from .wine_resolver import OriginWineWorker from .worker import Worker, QueueWorker diff --git a/rare/shared/workers/fetch.py b/rare/shared/workers/fetch.py index 01e08e09..449a5bf9 100644 --- a/rare/shared/workers/fetch.py +++ b/rare/shared/workers/fetch.py @@ -16,6 +16,7 @@ class FetchWorker(Worker): class Result(IntEnum): GAMES = 1 NON_ASSET = 2 + ORIGIN = 3 SAVES = 5 ENTITLEMENTS = 6 diff --git a/rare/shared/workers/wine_resolver.py b/rare/shared/workers/wine_resolver.py index ea0ef0cd..804d72d8 100644 --- a/rare/shared/workers/wine_resolver.py +++ b/rare/shared/workers/wine_resolver.py @@ -2,16 +2,18 @@ import os import platform import subprocess import time +from argparse import Namespace from configparser import ConfigParser from logging import getLogger from typing import Union, Iterator -from PyQt5.QtCore import pyqtSignal, QObject, QRunnable +from PyQt5.QtCore import pyqtSignal, QObject from rare.lgndr.core import LegendaryCore from rare.models.game import RareGame from rare.models.pathspec import PathSpec from rare.utils.misc import read_registry, path_size, format_size +from .fetch import FetchWorker from .worker import Worker if platform.system() == "Windows": @@ -35,9 +37,9 @@ class WineResolver(Worker): self.wine_env["DISPLAY"] = "" self.wine_binary = core.lgd.config.get( - app_name, - "wine_executable", - fallback=core.lgd.config.get("default", "wine_executable", fallback="wine"), + app_name, "wine_executable", fallback=core.lgd.config.get( + "default", "wine_executable", fallback="wine" + ) ) self.winepath_binary = os.path.join(os.path.dirname(self.wine_binary), "winepath") self.path = PathSpec(core, app_name).cook(path) @@ -82,19 +84,15 @@ class WineResolver(Worker): return -class OriginWineWorker(QRunnable): - def __init__(self, core: LegendaryCore, games: Union[Iterator[RareGame], RareGame]): - super().__init__() - self.setAutoDelete(True) - +class OriginWineWorker(FetchWorker): + def __init__(self, core: LegendaryCore, args: Namespace, games: Union[Iterator[RareGame], RareGame]): + super(OriginWineWorker, self).__init__(core, args) self.__cache: dict[str, ConfigParser] = {} if isinstance(games, RareGame): games = [games] - self.games = games - self.core = core - def run(self) -> None: + def run_real(self) -> None: t = time.time() for rgame in self.games: if not rgame.is_origin: @@ -109,16 +107,41 @@ class OriginWineWorker(QRunnable): if platform.system() == "Windows": install_dir = windows_helpers.query_registry_value(winreg.HKEY_LOCAL_MACHINE, reg_path, "Install Dir") else: - wine_prefix = self.core.lgd.config.get(rgame.app_name, "wine_prefix", - fallback=os.path.expanduser("~/.wine")) - reg = self.__cache.get(wine_prefix) or read_registry("system.reg", wine_prefix) + wine_prefix = self.core.lgd.config.get( + rgame.app_name, "wine_prefix", fallback=self.core.lgd.config.get( + "default", "wine_prefix", fallback=os.path.expanduser("~/.wine") + ) + ) + reg = self.__cache.get(wine_prefix, None) or read_registry("system.reg", wine_prefix) self.__cache[wine_prefix] = reg - # TODO: find a better solution - reg_path = reg_path.replace("\\", "\\\\") \ - .replace("SOFTWARE", "Software").replace("WOW6432Node", "Wow6432Node") + 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, '"Install Dir"', fallback=None) + if install_dir: + wine = self.core.lgd.config.get( + rgame.app_name, "wine_executable", fallback=self.core.lgd.config.get( + "default", "wine_executable", fallback="wine" + ) + ) + winepath = os.path.join(os.path.dirname(wine), "winepath") + wine_env = os.environ.copy() + wine_env.update(self.core.get_app_environment(rgame.app_name)) + wine_env["WINEDLLOVERRIDES"] = "winemenubuilder=d;mscoree=d;mshtml=d;" + wine_env["DISPLAY"] = "" + install_dir = install_dir.strip().strip('"') + proc = subprocess.Popen( + [winepath, "-u", install_dir], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + env=wine_env, + shell=False, + text=True, + ) + out, err = proc.communicate() + install_dir = os.path.realpath(out.strip()) if install_dir: if os.path.exists(install_dir): size = path_size(install_dir) @@ -126,4 +149,5 @@ class OriginWineWorker(QRunnable): logger.debug(f"Found Origin game {rgame.title} ({install_dir}, {format_size(size)})") else: logger.warning(f"Found Origin game {rgame.title} ({install_dir} does not exist)") + self.signals.result.emit((), FetchWorker.Result.ORIGIN) logger.info(f"Origin registry worker finished in {time.time() - t}s")