2022-12-24 09:49:27 +13:00
|
|
|
import os
|
2023-02-02 09:40:46 +13:00
|
|
|
import platform
|
2022-12-24 09:49:27 +13:00
|
|
|
import subprocess
|
2023-02-02 01:17:51 +13:00
|
|
|
import time
|
2023-03-08 09:53:18 +13:00
|
|
|
from argparse import Namespace
|
2023-02-02 01:17:51 +13:00
|
|
|
from configparser import ConfigParser
|
2023-01-26 00:04:21 +13:00
|
|
|
from logging import getLogger
|
2023-02-02 01:17:51 +13:00
|
|
|
from typing import Union, Iterator
|
2022-12-24 09:49:27 +13:00
|
|
|
|
2023-03-08 09:53:18 +13:00
|
|
|
from PyQt5.QtCore import pyqtSignal, QObject
|
2022-12-24 09:49:27 +13:00
|
|
|
|
2022-12-27 04:26:33 +13:00
|
|
|
from rare.lgndr.core import LegendaryCore
|
2023-02-02 01:17:51 +13:00
|
|
|
from rare.models.game import RareGame
|
2022-12-24 09:49:27 +13:00
|
|
|
from rare.models.pathspec import PathSpec
|
2023-02-02 11:02:46 +13:00
|
|
|
from rare.utils.misc import read_registry, path_size, format_size
|
2023-03-08 09:53:18 +13:00
|
|
|
from .fetch import FetchWorker
|
2023-02-01 00:59:22 +13:00
|
|
|
from .worker import Worker
|
2022-12-24 09:49:27 +13:00
|
|
|
|
2023-02-02 09:40:46 +13:00
|
|
|
if platform.system() == "Windows":
|
|
|
|
# noinspection PyUnresolvedReferences
|
|
|
|
import winreg # pylint: disable=E0401
|
|
|
|
from legendary.lfs import windows_helpers
|
|
|
|
|
2023-01-26 00:04:21 +13:00
|
|
|
logger = getLogger("WineResolver")
|
|
|
|
|
2022-12-24 09:49:27 +13:00
|
|
|
|
2023-02-01 00:59:22 +13:00
|
|
|
class WineResolver(Worker):
|
2022-12-24 09:49:27 +13:00
|
|
|
class Signals(QObject):
|
|
|
|
result_ready = pyqtSignal(str)
|
|
|
|
|
2022-12-27 04:26:33 +13:00
|
|
|
def __init__(self, core: LegendaryCore, path: str, app_name: str):
|
2022-12-24 09:49:27 +13:00
|
|
|
super(WineResolver, self).__init__()
|
|
|
|
self.signals = WineResolver.Signals()
|
|
|
|
self.wine_env = os.environ.copy()
|
|
|
|
self.wine_env.update(core.get_app_environment(app_name))
|
|
|
|
self.wine_env["WINEDLLOVERRIDES"] = "winemenubuilder=d;mscoree=d;mshtml=d;"
|
|
|
|
self.wine_env["DISPLAY"] = ""
|
|
|
|
|
|
|
|
self.wine_binary = core.lgd.config.get(
|
2023-03-08 09:53:18 +13:00
|
|
|
app_name, "wine_executable", fallback=core.lgd.config.get(
|
|
|
|
"default", "wine_executable", fallback="wine"
|
|
|
|
)
|
2022-12-24 09:49:27 +13:00
|
|
|
)
|
|
|
|
self.winepath_binary = os.path.join(os.path.dirname(self.wine_binary), "winepath")
|
|
|
|
self.path = PathSpec(core, app_name).cook(path)
|
|
|
|
|
2023-02-01 00:59:22 +13:00
|
|
|
def run_real(self):
|
2022-12-24 09:49:27 +13:00
|
|
|
if "WINEPREFIX" not in self.wine_env or not os.path.exists(self.wine_env["WINEPREFIX"]):
|
|
|
|
# pylint: disable=E1136
|
|
|
|
self.signals.result_ready[str].emit("")
|
|
|
|
return
|
|
|
|
if not os.path.exists(self.wine_binary) or not os.path.exists(self.winepath_binary):
|
|
|
|
# pylint: disable=E1136
|
|
|
|
self.signals.result_ready[str].emit("")
|
|
|
|
return
|
|
|
|
path = self.path.strip().replace("/", "\\")
|
|
|
|
# lk: if path does not exist form
|
|
|
|
cmd = [self.wine_binary, "cmd", "/c", "echo", path]
|
|
|
|
# lk: if path exists and needs a case-sensitive interpretation form
|
|
|
|
# cmd = [self.wine_binary, 'cmd', '/c', f'cd {path} & cd']
|
|
|
|
proc = subprocess.Popen(
|
|
|
|
cmd,
|
|
|
|
stdout=subprocess.PIPE,
|
|
|
|
stderr=subprocess.PIPE,
|
|
|
|
env=self.wine_env,
|
|
|
|
shell=False,
|
|
|
|
text=True,
|
|
|
|
)
|
|
|
|
out, err = proc.communicate()
|
|
|
|
# Clean wine output
|
|
|
|
out = out.strip().strip('"')
|
|
|
|
proc = subprocess.Popen(
|
|
|
|
[self.winepath_binary, "-u", out],
|
|
|
|
stdout=subprocess.PIPE,
|
|
|
|
stderr=subprocess.PIPE,
|
|
|
|
env=self.wine_env,
|
|
|
|
shell=False,
|
|
|
|
text=True,
|
|
|
|
)
|
|
|
|
out, err = proc.communicate()
|
|
|
|
real_path = os.path.realpath(out.strip())
|
|
|
|
# pylint: disable=E1136
|
|
|
|
self.signals.result_ready[str].emit(real_path)
|
|
|
|
return
|
2023-02-02 01:17:51 +13:00
|
|
|
|
|
|
|
|
2023-03-08 09:53:18 +13:00
|
|
|
class OriginWineWorker(FetchWorker):
|
|
|
|
def __init__(self, core: LegendaryCore, args: Namespace, games: Union[Iterator[RareGame], RareGame]):
|
|
|
|
super(OriginWineWorker, self).__init__(core, args)
|
2023-02-02 01:17:51 +13:00
|
|
|
self.__cache: dict[str, ConfigParser] = {}
|
|
|
|
if isinstance(games, RareGame):
|
|
|
|
games = [games]
|
|
|
|
self.games = games
|
|
|
|
|
2023-03-08 09:53:18 +13:00
|
|
|
def run_real(self) -> None:
|
2023-02-02 01:17:51 +13:00
|
|
|
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
|
|
|
|
|
2023-02-02 09:40:46 +13:00
|
|
|
if platform.system() == "Windows":
|
|
|
|
install_dir = windows_helpers.query_registry_value(winreg.HKEY_LOCAL_MACHINE, reg_path, "Install Dir")
|
|
|
|
else:
|
2023-03-08 09:53:18 +13:00
|
|
|
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)
|
2023-02-02 09:40:46 +13:00
|
|
|
self.__cache[wine_prefix] = reg
|
2023-02-02 01:17:51 +13:00
|
|
|
|
2023-03-08 09:53:18 +13:00
|
|
|
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)])
|
2023-02-02 01:17:51 +13:00
|
|
|
|
2023-02-02 09:40:46 +13:00
|
|
|
install_dir = reg.get(reg_path, '"Install Dir"', fallback=None)
|
2023-03-08 09:53:18 +13:00
|
|
|
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())
|
2023-02-02 01:17:51 +13:00
|
|
|
if install_dir:
|
2023-02-02 11:02:46 +13:00
|
|
|
if os.path.exists(install_dir):
|
|
|
|
size = path_size(install_dir)
|
|
|
|
rgame.set_origin_attributes(install_dir, size)
|
|
|
|
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)")
|
2023-03-08 09:53:18 +13:00
|
|
|
self.signals.result.emit((), FetchWorker.Result.ORIGIN)
|
2023-02-02 01:17:51 +13:00
|
|
|
logger.info(f"Origin registry worker finished in {time.time() - t}s")
|