Skip to content

Commit

Permalink
Wrappers/Proton/Wine WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
loathingKernel committed Sep 24, 2023
1 parent 6fcde29 commit 00a81d1
Show file tree
Hide file tree
Showing 21 changed files with 978 additions and 534 deletions.
22 changes: 11 additions & 11 deletions rare/components/tabs/games/game_info/cloud_saves.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from logging import getLogger
from typing import Tuple

from PyQt5.QtCore import QThreadPool, QSettings
from PyQt5.QtCore import QThreadPool, QSettings, pyqtSlot
from PyQt5.QtWidgets import (
QWidget,
QFileDialog,
Expand All @@ -19,10 +19,11 @@

from rare.models.game import RareGame
from rare.shared import RareCore
from rare.shared.workers.wine_resolver import WineResolver
from rare.shared.workers.wine_resolver import WineSavePathResolver
from rare.ui.components.tabs.games.game_info.cloud_widget import Ui_CloudWidget
from rare.ui.components.tabs.games.game_info.sync_widget import Ui_SyncWidget
from rare.utils.misc import icon
from rare.utils.metrics import timelogger
from rare.widgets.indicator_edit import PathEdit, IndicatorReasonsCommon
from rare.widgets.loading_widget import LoadingWidget
from rare.widgets.side_tab import SideTabContents
Expand Down Expand Up @@ -110,13 +111,14 @@ def download(self):
def compute_save_path(self):
if self.rgame.is_installed and self.rgame.game.supports_cloud_saves:
try:
new_path = self.core.get_save_path(self.rgame.app_name)
with timelogger(logger, "Detecting save path"):
new_path = self.core.get_save_path(self.rgame.app_name)
if platform.system() != "Windows" and not os.path.exists(new_path):
raise ValueError(f'Path "{new_path}" does not exist.')
except Exception as e:
logger.warning(str(e))
resolver = WineResolver(self.core, self.rgame.raw_save_path, self.rgame.app_name)
if not resolver.wine_env.get("WINEPREFIX"):
resolver = WineSavePathResolver(self.core, self.rgame)
if not resolver.environment.get("WINEPREFIX"):
del resolver
self.cloud_save_path_edit.setText("")
QMessageBox.warning(self, "Warning", "No wine prefix selected. Please set it in settings")
Expand All @@ -125,21 +127,21 @@ def compute_save_path(self):
self.cloud_save_path_edit.setDisabled(True)
self.compute_save_path_button.setDisabled(True)

app_name = self.rgame.app_name
resolver.signals.result_ready.connect(lambda x: self.wine_resolver_finished(x, app_name))
resolver.signals.result_ready.connect(self.__on_wine_resolver_result)
QThreadPool.globalInstance().start(resolver)
return
else:
self.cloud_save_path_edit.setText(new_path)

def wine_resolver_finished(self, path, app_name):
@pyqtSlot(str, str)
def __on_wine_resolver_result(self, path, app_name):
logger.info(f"Wine resolver finished for {app_name}. Computed save path: {path}")
if app_name == self.rgame.app_name:
self.cloud_save_path_edit.setDisabled(False)
self.compute_save_path_button.setDisabled(False)
if path and not os.path.exists(path):
try:
os.makedirs(path)
os.makedirs(path, exist_ok=True)
except PermissionError:
self.cloud_save_path_edit.setText("")
QMessageBox.warning(
Expand All @@ -154,8 +156,6 @@ def wine_resolver_finished(self, path, app_name):
self.cloud_save_path_edit.setText("")
return
self.cloud_save_path_edit.setText(path)
elif path:
self.rcore.get_game(app_name).save_path = path

def __update_widget(self):
supports_saves = self.rgame.igame is not None and (
Expand Down
4 changes: 2 additions & 2 deletions rare/components/tabs/games/integrations/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from typing import Optional

from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QVBoxLayout, QWidget, QLabel, QSpacerItem, QSizePolicy
from PyQt5.QtWidgets import QVBoxLayout, QWidget, QLabel, QSizePolicy

from rare.widgets.side_tab import SideTabWidget
from .egl_sync_group import EGLSyncGroup
Expand Down Expand Up @@ -34,8 +34,8 @@ def __init__(self, parent=None):
self.tr(""),
self,
)
self.ubisoft_group = UbisoftGroup(self.eos_ubisoft)
self.eos_group = EosGroup(self.eos_ubisoft)
self.ubisoft_group = UbisoftGroup(self.eos_ubisoft)
self.eos_ubisoft.addWidget(self.eos_group)
self.eos_ubisoft.addWidget(self.ubisoft_group)
self.eos_ubisoft_index = self.addTab(self.eos_ubisoft, self.tr("Epic Overlay and Ubisoft"))
Expand Down
54 changes: 29 additions & 25 deletions rare/components/tabs/games/integrations/egl_sync_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@
from rare.lgndr.glue.exception import LgndrException
from rare.models.pathspec import PathSpec
from rare.shared import RareCore
from rare.shared.workers.wine_resolver import WineResolver
from rare.shared.workers.wine_resolver import WinePathResolver
from rare.ui.components.tabs.games.integrations.egl_sync_group import Ui_EGLSyncGroup
from rare.ui.components.tabs.games.integrations.egl_sync_list_group import Ui_EGLSyncListGroup
from rare.utils import runners
from rare.widgets.elide_label import ElideLabel
from rare.widgets.indicator_edit import PathEdit, IndicatorReasonsCommon

Expand Down Expand Up @@ -56,16 +57,9 @@ def __init__(self, parent=None):
self.egl_path_info.setEnabled(False)
else:
self.egl_path_edit.textChanged.connect(self.egl_path_changed)
if not self.core.egl.programdata_path:
self.egl_path_info.setText(self.tr("Updating..."))
wine_resolver = WineResolver(
self.core, PathSpec.egl_programdata, "default"
)
wine_resolver.signals.result_ready.connect(self.wine_resolver_cb)
QThreadPool.globalInstance().start(wine_resolver)
else:
self.egl_path_info_label.setVisible(False)
self.egl_path_info.setVisible(False)
if self.core.egl.programdata_path:
self.egl_path_info_label.setEnabled(True)
self.egl_path_info.setEnabled(True)

self.ui.egl_sync_check.setChecked(self.core.egl_sync_enabled)
self.ui.egl_sync_check.stateChanged.connect(self.egl_sync_changed)
Expand All @@ -79,10 +73,24 @@ def __init__(self, parent=None):
# self.egl_watcher.directoryChanged.connect(self.update_lists)

def showEvent(self, a0: QShowEvent) -> None:
if a0.spontaneous():
return super().showEvent(a0)
if not self.core.egl.programdata_path:
self.__run_wine_resolver()
self.update_lists()
super().showEvent(a0)

def wine_resolver_cb(self, path):
def __run_wine_resolver(self):
self.egl_path_info.setText(self.tr("Updating..."))
wine_resolver = WinePathResolver(
self.core.get_app_launch_command("default"),
runners.get_environment(self.core.get_app_environment("default")),
PathSpec.egl_programdata()
)
wine_resolver.signals.result_ready.connect(self.__on_wine_resolver_result)
QThreadPool.globalInstance().start(wine_resolver)

def __on_wine_resolver_result(self, path):
self.egl_path_info.setText(path)
if not path:
self.egl_path_info.setText(
Expand All @@ -109,14 +117,8 @@ def egl_path_edit_edit_cb(path) -> Tuple[bool, str, int]:
os.path.join(path, "dosdevices/c:")
):
# path is a wine prefix
path = os.path.join(
path,
"dosdevices/c:",
"ProgramData/Epic/EpicGamesLauncher/Data/Manifests",
)
elif not path.rstrip("/").endswith(
"ProgramData/Epic/EpicGamesLauncher/Data/Manifests"
):
path = PathSpec.prefix_egl_programdata(path)
elif not path.rstrip("/").endswith(PathSpec.wine_egl_programdata()):
# lower() might or might not be needed in the check
return False, path, IndicatorReasonsCommon.WRONG_FORMAT
if os.path.exists(path):
Expand Down Expand Up @@ -166,13 +168,15 @@ def egl_sync_changed(self, state):

def update_lists(self):
# self.egl_watcher.blockSignals(True)
if have_path := bool(self.core.egl.programdata_path) and os.path.exists(self.core.egl.programdata_path):
have_path = False
if self.core.egl.programdata_path:
have_path = os.path.exists(self.core.egl.programdata_path)
if not have_path and os.path.isdir(os.path.dirname(self.core.egl.programdata_path)):
# NOTE: This might happen if EGL is installed but no games have been installed through it
os.mkdir(self.core.egl.programdata_path)
have_path = os.path.isdir(self.core.egl.programdata_path)
# NOTE: need to clear known manifests to force refresh
self.core.egl.manifests.clear()
elif os.path.isdir(os.path.dirname(self.core.egl.programdata_path)):
# NOTE: This might happen if EGL is installed but no games have been installed through it
os.mkdir(self.core.egl.programdata_path)
have_path = bool(self.core.egl.programdata_path) and os.path.isdir(self.core.egl.programdata_path)
self.ui.egl_sync_check_label.setEnabled(have_path)
self.ui.egl_sync_check.setEnabled(have_path)
self.import_list.populate(have_path)
Expand Down
42 changes: 30 additions & 12 deletions rare/components/tabs/games/integrations/eos_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from rare.models.game import RareEosOverlay
from rare.shared import RareCore
from rare.ui.components.tabs.games.integrations.eos_widget import Ui_EosWidget
from rare.utils import config_helper
from rare.utils import config_helper as config
from rare.utils.misc import icon
from rare.widgets.elide_label import ElideLabel

Expand Down Expand Up @@ -51,7 +51,10 @@ def __init__(self, overlay: RareEosOverlay, prefix: Optional[str], parent=None):
self.indicator = QLabel(parent=self)
self.indicator.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Preferred)

self.prefix_label = ElideLabel(prefix if prefix is not None else overlay.app_title, parent=self)
self.prefix_label = ElideLabel(
prefix.replace(os.path.expanduser("~"), "~") if prefix is not None else overlay.app_title,
parent=self,
)
self.overlay_label = ElideLabel(parent=self)
self.overlay_label.setDisabled(True)

Expand Down Expand Up @@ -128,10 +131,14 @@ def action(self) -> None:
if self.overlay.is_enabled(self.prefix) and (path == active_path):
if not self.overlay.disable(prefix=self.prefix):
QMessageBox.warning(
self, "Warning",
self,
"Warning",
self.tr("Failed to completely disable the active EOS Overlay.{}").format(
self.tr(" Since the previous overlay was managed by EGL you can safely ignore this is.")
if active_path != install_path else ""
self.tr(
" Since the previous overlay was managed by EGL you can safely ignore this is."
)
if active_path != install_path
else ""
),
)
else:
Expand All @@ -141,7 +148,9 @@ def action(self) -> None:
self,
"Warning",
self.tr("Failed to completely enable EOS overlay.{}").format(
self.tr(" Since the previous overlay was managed by EGL you can safely ignore this is.")
self.tr(
" Since the previous overlay was managed by EGL you can safely ignore this is."
)
if active_path != install_path
else ""
),
Expand Down Expand Up @@ -191,8 +200,11 @@ def __init__(self, parent=None):
self.ui.update_button.setEnabled(False)

self.threadpool = QThreadPool.globalInstance()
self.worker: Optional[CheckForUpdateWorker] = None

def showEvent(self, a0) -> None:
if a0.spontaneous():
return super().showEvent(a0)
self.check_for_update()
self.update_prefixes()
super().showEvent(a0)
Expand All @@ -202,7 +214,8 @@ def update_prefixes(self):
widget.deleteLater()

if platform.system() != "Windows":
prefixes = config_helper.get_wine_prefixes()
prefixes = config.get_prefixes()
prefixes = {prefix for prefix in prefixes if config.prefix_exists(prefix)}
if platform.system() == "Darwin":
# TODO: add crossover support
pass
Expand All @@ -214,16 +227,21 @@ def update_prefixes(self):
widget = EosPrefixWidget(self.overlay, None)
self.ui.eos_layout.addWidget(widget)

@pyqtSlot(bool)
def worker_finished(self, update_available: bool):
self.worker = None
self.ui.update_button.setEnabled(update_available)

def check_for_update(self):
if not self.overlay.is_installed:
return

def worker_finished(update_available):
self.ui.update_button.setEnabled(update_available)
if self.worker is not None:
return

worker = CheckForUpdateWorker(self.core)
worker.signals.update_available.connect(worker_finished)
QThreadPool.globalInstance().start(worker)
self.worker = CheckForUpdateWorker(self.core)
self.worker.signals.update_available.connect(self.worker_finished)
QThreadPool.globalInstance().start(self.worker)

@pyqtSlot()
def install_finished(self):
Expand Down
Loading

0 comments on commit 00a81d1

Please sign in to comment.