diff --git a/rare/components/tabs/games/__init__.py b/rare/components/tabs/games/__init__.py index 25fd575b..a2f44830 100644 --- a/rare/components/tabs/games/__init__.py +++ b/rare/components/tabs/games/__init__.py @@ -1,6 +1,7 @@ +import platform from logging import getLogger -from PyQt5.QtCore import QSettings, Qt, pyqtSlot +from PyQt5.QtCore import QSettings, Qt, pyqtSlot, QThreadPool from PyQt5.QtWidgets import QStackedWidget, QVBoxLayout, QWidget, QScrollArea, QFrame from rare.models.game import RareGame @@ -11,6 +12,7 @@ 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 @@ -154,6 +156,11 @@ class GamesTab(QStackedWidget): self.filter_games(self.active_filter) self.update_count_games_label() + if platform.system() != "Windows": + worker = OriginWineWorker(self.rcore.origin_games, self.core) + 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/head_bar.py b/rare/components/tabs/games/head_bar.py index 91c9118c..6cc2eb16 100644 --- a/rare/components/tabs/games/head_bar.py +++ b/rare/components/tabs/games/head_bar.py @@ -46,7 +46,7 @@ class GameListHeadBar(QWidget): self.filter.addItem(self.tr("Mac games")) self.available_filters.append("mac") - if self.rcore.no_asset_games: + if self.rcore.origin_games: self.filter.addItem(self.tr("Exclude Origin")) self.available_filters.append("installable") diff --git a/rare/models/game.py b/rare/models/game.py index 575d3957..1606a1cb 100644 --- a/rare/models/game.py +++ b/rare/models/game.py @@ -2,7 +2,6 @@ import json import os import platform from abc import abstractmethod -import time from dataclasses import dataclass, field from datetime import datetime from enum import IntEnum @@ -17,7 +16,6 @@ from rare.lgndr.core import LegendaryCore from rare.models.install import InstallOptionsModel, UninstallOptionsModel from rare.shared.game_process import GameProcess from rare.shared.image_manager import ImageManager -from rare.utils.misc import read_registry from rare.utils.paths import data_dir, get_rare_executable from rare.utils.steam_grades import get_rating @@ -139,6 +137,7 @@ class RareGameSlim(RareGameBase): self.igame: Optional[InstalledGame] = self.core.get_installed_game(game.app_name) self.saves: List[SaveGameFile] = [] + @property def is_installed(self) -> bool: return True @@ -201,6 +200,9 @@ class RareGame(RareGameSlim): def __init__(self, legendary_core: LegendaryCore, image_manager: ImageManager, game: Game): super(RareGame, self).__init__(legendary_core, game) + self.__origin_install_path: Optional[str] = None + self.__steam_grade: Optional[str] = None + self.image_manager = image_manager # Update names for Unreal Engine @@ -227,7 +229,15 @@ class RareGame(RareGameSlim): if self.is_installed and not self.is_dlc: self.game_process.connect_to_server(on_startup=True) - self.__steam_grade: Optional[str] = None + if platform.system() == "Windows" and self.is_origin: + reg_path: str = self.game.metadata \ + .get("customAttributes", {}) \ + .get("RegistryPath", {}).get("value", None) + if not reg_path: + return + install_dir = windows_helpers.query_registry_value(winreg.HKEY_LOCAL_MACHINE, reg_path, "Install Dir") + self.__origin_install_path = install_dir + self.set_origin_attributes(install_dir) def __on_progress_update(self, progress: int): self.progress = progress @@ -326,7 +336,7 @@ class RareGame(RareGameSlim): return self.igame.install_path elif self.is_origin: # TODO Linux is also C:\\... - return self.__get_origin_install_path() + return self.__origin_install_path return None @install_path.setter @@ -396,7 +406,7 @@ class RareGame(RareGameSlim): @return bool If the game should be considered installed """ return (self.igame is not None) \ - or (self.is_origin and self.__get_origin_install_path() is not None) + or (self.is_origin and self.__origin_install_path is not None) def set_installed(self, installed: bool) -> None: """! @@ -607,47 +617,14 @@ class RareGame(RareGameSlim): ) return True - __registry_cache: Dict = {} - __origin_install_path = None - - def __get_origin_install_path(self) -> Optional[str]: - if self.__origin_install_path == "": - return None - elif self.__origin_install_path: - return self.__origin_install_path - reg_path: str = self.game.metadata \ - .get("customAttributes", {}) \ - .get("RegistryPath", {}).get("value", None) - if not reg_path: - return None - - if platform.system() == "Windows": - install_dir = windows_helpers.query_registry_value(winreg.HKEY_LOCAL_MACHINE, reg_path, "Install Dir") - self.__origin_install_path = install_dir - return install_dir - - wine_prefix = self.core.lgd.config.get(self.game.app_name, "wine_prefix", - fallback=os.path.expanduser("~/.wine")) - - # TODO cache this line - t = time.time() - if wine_prefix in RareGame.__registry_cache.keys(): - reg = RareGame.__registry_cache[wine_prefix] + def set_origin_attributes(self, path: str) -> None: + self.__origin_install_path = path + if self.install_path: + self.signals.game.installed.emit(self.app_name) else: - reg = read_registry("system.reg", wine_prefix) - RareGame.__registry_cache[wine_prefix] = reg - logger.debug(f"Read reg file {self.app_name}: {time.time() - t}s") - - # TODO: find a better solution - reg_path = reg_path.replace("\\", "\\\\").replace("SOFTWARE", "Software").replace("WOW6432Node", "Wow6432Node") - install_dir = reg.get(reg_path, '"Install Dir"', fallback=None) - - if install_dir: - install_dir = install_dir.strip('"') - self.__origin_install_path = install_dir - return install_dir - self.__origin_install_path = "" - return None + self.signals.game.uninstalled.emit(self.app_name) + self.set_pixmap() + self.signals.widget.update.emit() def repair(self, repair_and_update): self.signals.game.install.emit( diff --git a/rare/shared/rare_core.py b/rare/shared/rare_core.py index 141f44bf..79235c6f 100644 --- a/rare/shared/rare_core.py +++ b/rare/shared/rare_core.py @@ -369,6 +369,10 @@ class RareCore(QObject): def installed_games(self) -> Iterator[RareGame]: return self.__filter_games(lambda game: game.is_installed and not game.is_dlc) + @property + def origin_games(self) -> Iterator[RareGame]: + return self.__filter_games(lambda game: game.is_origin and not game.is_dlc) + @property def game_list(self) -> Iterator[Game]: for game in self.games: @@ -398,7 +402,7 @@ class RareCore(QObject): return self.__filter_games(lambda game: game.is_mac) @property - def no_asset_games(self) -> Iterator[RareGame]: + def non_asset_games(self) -> Iterator[RareGame]: return self.__filter_games(lambda game: game.is_non_asset) @property diff --git a/rare/shared/workers/wine_resolver.py b/rare/shared/workers/wine_resolver.py index 695edaf4..08021726 100644 --- a/rare/shared/workers/wine_resolver.py +++ b/rare/shared/workers/wine_resolver.py @@ -1,11 +1,16 @@ import os import subprocess +import time +from configparser import ConfigParser from logging import getLogger +from typing import Union, Iterator -from PyQt5.QtCore import pyqtSignal, QObject +from PyQt5.QtCore import pyqtSignal, QObject, QRunnable 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 from .worker import Worker logger = getLogger("WineResolver") @@ -69,3 +74,43 @@ class WineResolver(Worker): # pylint: disable=E1136 self.signals.result_ready[str].emit(real_path) return + + +class OriginWineWorker(QRunnable): + def __init__(self, games: Union[Iterator[RareGame], RareGame], core: LegendaryCore): + super().__init__() + self.setAutoDelete(True) + + self.__cache: dict[str, ConfigParser] = {} + if isinstance(games, RareGame): + games = [games] + + self.games = games + self.core = core + + def run(self) -> None: + t = time.time() + for rgame in self.games: + if not rgame.is_origin: + continue + + reg_path: str = rgame.game.metadata \ + .get("customAttributes", {}) \ + .get("RegistryPath", {}).get("value", None) + if not reg_path: + continue + + 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) + self.__cache[wine_prefix] = reg + + # TODO: find a better solution + reg_path = reg_path.replace("\\", "\\\\")\ + .replace("SOFTWARE", "Software").replace("WOW6432Node", "Wow6432Node") + + install_dir = reg.get(reg_path, '"Install Dir"', fallback=None) + if install_dir: + logger.debug(f"Found install path for {rgame.title}: {install_dir}") + rgame.set_origin_attributes(install_dir) + logger.info(f"Origin registry worker finished in {time.time() - t}s")