1
0
Fork 0
mirror of synced 2024-06-02 18:54:41 +12:00
Rare/rare/components/tabs/games/game_widgets/base_installed_widget.py
2022-06-22 16:53:26 +03:00

250 lines
9.7 KiB
Python

import os
import platform
from logging import getLogger
from PyQt5.QtCore import pyqtSignal, QProcess, QSettings, QStandardPaths, Qt, QByteArray
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import QFrame, QMessageBox, QAction
from rare.components.tabs.games.game_utils import GameUtils
from rare.shared import LegendaryCoreSingleton, GlobalSignalsSingleton, ArgumentsSingleton
from rare.shared.image_manager import ImageManagerSingleton, ImageSize
from rare.utils.utils import create_desktop_link
from rare.widgets.image_widget import ImageWidget
logger = getLogger("Game")
class BaseInstalledWidget(QFrame):
launch_signal = pyqtSignal(str, QProcess, list)
show_info = pyqtSignal(str)
finish_signal = pyqtSignal(str, int)
proc: QProcess()
def __init__(self, app_name, pixmap: QPixmap, game_utils: GameUtils):
super(BaseInstalledWidget, self).__init__()
self.core = LegendaryCoreSingleton()
self.signals = GlobalSignalsSingleton()
self.args = ArgumentsSingleton()
self.image_manager = ImageManagerSingleton()
self.game_utils = game_utils
self.syncing_cloud_saves = False
self.texts = {
"needs_verification": self.tr("Please verify game before playing"),
"hover": {
"update_available": self.tr("Start game without version check"),
"launch": self.tr("Launch Game"),
"launch_origin": self.tr("Launch/Link"),
"running": self.tr("Game running"),
"launch_offline": self.tr("Launch offline")
},
"default": {
"running": self.tr("Game running"),
"syncing": self.tr("Syncing cloud saves"),
"update_available": self.tr("Update available"),
"no_meta": self.tr("Game is only offline available")
},
}
self.game = self.core.get_game(app_name)
self.igame = self.core.get_installed_game(app_name) # None if origin
if self.game.app_title == "Unreal Engine":
self.game.app_title = f"{self.game.app_title} {self.game.app_name.split('_')[-1]}"
self.is_only_offline = False
try:
self.core.get_asset(app_name, platform=self.igame.platform).build_version
except ValueError:
logger.warning(f"Game {self.game.app_title} has no metadata. Set offline true")
self.is_only_offline = True
except AttributeError:
pass
self.image = ImageWidget(self)
self.image.setFixedSize(ImageSize.Display)
self.image.setPixmap(pixmap)
self.game_running = False
self.offline = self.args.offline
self.update_available = False
if self.igame and self.core.lgd.assets:
try:
remote_version = self.core.get_asset(
self.game.app_name, platform=self.igame.platform, update=False
).build_version
except ValueError:
logger.error(f"Asset error for {self.game.app_title}")
self.update_available = False
else:
if remote_version != self.igame.version:
self.update_available = True
self.data = QByteArray()
self.settings = QSettings()
self.setContextMenuPolicy(Qt.ActionsContextMenu)
launch = QAction(self.tr("Launch"), self)
launch.triggered.connect(self.launch)
self.addAction(launch)
if self.game.supports_cloud_saves:
sync = QAction(self.tr("Sync with cloud"), self)
sync.triggered.connect(self.sync_game)
self.addAction(sync)
desktop = QStandardPaths.writableLocation(QStandardPaths.DesktopLocation)
if os.path.exists(
os.path.join(desktop, f"{self.game.app_title}.desktop")
) or os.path.exists(os.path.join(desktop, f"{self.game.app_title}.lnk")):
self.create_desktop = QAction(self.tr("Remove Desktop link"))
else:
self.create_desktop = QAction(self.tr("Create Desktop link"))
if self.igame:
self.create_desktop.triggered.connect(
lambda: self.create_desktop_link("desktop")
)
self.addAction(self.create_desktop)
applications = QStandardPaths.writableLocation(QStandardPaths.ApplicationsLocation)
if platform.system() == "Linux":
start_menu_file = os.path.join(applications, f"{self.game.app_title}.desktop")
elif platform.system() == "Windows":
start_menu_file = os.path.join(applications, "..", f"{self.game.app_title}.lnk")
else:
start_menu_file = ""
if platform.system() in ["Windows", "Linux"]:
if os.path.exists(start_menu_file):
self.create_start_menu = QAction(self.tr("Remove start menu link"))
else:
self.create_start_menu = QAction(self.tr("Create start menu link"))
if self.igame:
self.create_start_menu.triggered.connect(
lambda: self.create_desktop_link("start_menu")
)
self.addAction(self.create_start_menu)
reload_image = QAction(self.tr("Reload Image"), self)
reload_image.triggered.connect(self.reload_image)
self.addAction(reload_image)
if self.igame is not None:
uninstall = QAction(self.tr("Uninstall"), self)
self.addAction(uninstall)
uninstall.triggered.connect(
lambda: self.signals.update_gamelist.emit([self.game.app_name])
if self.game_utils.uninstall_game(self.game.app_name)
else None
)
def reload_image(self):
self.image_manager.download_image_blocking(self.game, force=True)
pm = self.image_manager.get_pixmap(self.game.app_name, color=True)
self.image.setPixmap(pm)
def create_desktop_link(self, type_of_link):
if type_of_link == "desktop":
shortcut_path = QStandardPaths.writableLocation(QStandardPaths.DesktopLocation)
elif type_of_link == "start_menu":
shortcut_path = QStandardPaths.writableLocation(QStandardPaths.ApplicationsLocation)
else:
return
if platform.system() == "Windows":
shortcut_path = os.path.join(shortcut_path, f"{self.game.app_title}.lnk")
elif platform.system() == "Linux":
shortcut_path = os.path.join(shortcut_path, f"{self.game.app_title}.desktop")
else:
QMessageBox.warning(
self,
"Warning",
f"Create a Desktop link is currently not supported on {platform.system()}",
)
return
if not os.path.exists(shortcut_path):
try:
if not create_desktop_link(self.game.app_name, self.core, type_of_link):
return
except PermissionError:
QMessageBox.warning(
self, "Error", "Permission error. Cannot create Desktop Link"
)
if type_of_link == "desktop":
self.create_desktop.setText(self.tr("Remove Desktop link"))
elif type_of_link == "start_menu":
self.create_start_menu.setText(self.tr("Remove Start menu link"))
else:
if os.path.exists(shortcut_path):
os.remove(shortcut_path)
if type_of_link == "desktop":
self.create_desktop.setText(self.tr("Create Desktop link"))
elif type_of_link == "start_menu":
self.create_start_menu.setText(self.tr("Create Start menu link"))
def launch(self, offline=False, skip_version_check=False):
if self.game_running:
return
offline = offline or self.is_only_offline
if self.is_only_offline and not self.igame.can_run_offline:
QMessageBox.warning(self, "Warning",
self.tr("This game is probably not in your library and it cannot be launched offline"))
return
if self.game.supports_cloud_saves and not offline:
self.syncing_cloud_saves = True
self.game_utils.prepare_launch(
self.game.app_name, offline, skip_version_check
)
def sync_finished(self, app_name):
self.syncing_cloud_saves = False
def sync_game(self):
try:
sync = self.game_utils.cloud_save_utils.sync_before_launch_game(
self.game.app_name, True
)
except Exception:
sync = False
if sync:
self.syncing_cloud_saves = True
def game_finished(self, app_name, error):
if error:
QMessageBox.warning(self, "Error", error)
self.game_running = False
# From RareGame, added from sorting to work
@property
def is_non_asset(self) -> bool:
"""!
@brief Property to report if a Game doesn't have assets
Typically, games have assets, however some games that require
other launchers do not have them. Rare treats these games as installed
offering to execute their launcher.
@return bool If the game doesn't have assets
"""
return not self.game.asset_infos
@property
def is_installed(self) -> bool:
"""!
@brief Property to report if a game is installed
This returns True if InstalledGame data have been loaded for the game
or if the game is a game without assets, for example an Origin game.
@return bool If the game should be considered installed
"""
return (self.igame is not None) or self.is_non_asset
@property
def app_title(self) -> str:
return self.igame.title if self.igame is not None else self.game.app_title