2021-11-02 10:53:04 +13:00
|
|
|
import os
|
2022-12-27 02:11:23 +13:00
|
|
|
import platform
|
2021-11-02 10:53:04 +13:00
|
|
|
from logging import getLogger
|
|
|
|
|
2023-01-11 08:40:57 +13:00
|
|
|
from PyQt5.QtCore import QObject, QProcess, pyqtSignal, QUrl, pyqtSlot
|
2022-12-27 02:11:23 +13:00
|
|
|
from PyQt5.QtCore import QStandardPaths
|
2022-03-28 08:52:32 +13:00
|
|
|
from PyQt5.QtGui import QDesktopServices
|
2021-11-02 10:53:04 +13:00
|
|
|
from PyQt5.QtWidgets import QMessageBox, QPushButton
|
2022-12-27 02:11:23 +13:00
|
|
|
from legendary.core import LegendaryCore
|
2021-11-02 10:53:04 +13:00
|
|
|
|
|
|
|
from rare.components.dialogs.uninstall_dialog import UninstallDialog
|
2022-12-27 02:11:23 +13:00
|
|
|
from rare.lgndr.cli import LegendaryCLI
|
|
|
|
from rare.lgndr.glue.arguments import LgndrUninstallGameArgs
|
|
|
|
from rare.lgndr.glue.monkeys import LgndrIndirectStatus
|
2023-01-05 09:33:30 +13:00
|
|
|
from rare.models.game import RareGame
|
2022-03-28 08:52:32 +13:00
|
|
|
from rare.shared import LegendaryCoreSingleton, GlobalSignalsSingleton, ArgumentsSingleton
|
2023-01-11 08:40:57 +13:00
|
|
|
from rare.shared.game_process import GameProcess
|
2022-12-27 02:11:23 +13:00
|
|
|
from rare.utils import config_helper, misc
|
|
|
|
from .cloud_save_utils import CloudSaveUtils
|
2021-11-02 10:53:04 +13:00
|
|
|
|
|
|
|
logger = getLogger("GameUtils")
|
|
|
|
|
|
|
|
|
2022-12-27 02:11:23 +13:00
|
|
|
def uninstall_game(core: LegendaryCore, app_name: str, keep_files=False, keep_config=False):
|
|
|
|
igame = core.get_installed_game(app_name)
|
|
|
|
|
|
|
|
# remove shortcuts link
|
|
|
|
desktop = QStandardPaths.writableLocation(QStandardPaths.DesktopLocation)
|
|
|
|
applications = QStandardPaths.writableLocation(QStandardPaths.ApplicationsLocation)
|
|
|
|
if platform.system() == "Linux":
|
|
|
|
desktop_shortcut = os.path.join(desktop, f"{igame.title}.desktop")
|
|
|
|
if os.path.exists(desktop_shortcut):
|
|
|
|
os.remove(desktop_shortcut)
|
|
|
|
|
|
|
|
applications_shortcut = os.path.join(applications, f"{igame.title}.desktop")
|
|
|
|
if os.path.exists(applications_shortcut):
|
|
|
|
os.remove(applications_shortcut)
|
|
|
|
|
|
|
|
elif platform.system() == "Windows":
|
|
|
|
game_title = igame.title.split(":")[0]
|
|
|
|
desktop_shortcut = os.path.join(desktop, f"{game_title}.lnk")
|
|
|
|
if os.path.exists(desktop_shortcut):
|
|
|
|
os.remove(desktop_shortcut)
|
|
|
|
|
|
|
|
start_menu_shortcut = os.path.join(applications, "..", f"{game_title}.lnk")
|
|
|
|
if os.path.exists(start_menu_shortcut):
|
|
|
|
os.remove(start_menu_shortcut)
|
|
|
|
|
|
|
|
status = LgndrIndirectStatus()
|
|
|
|
LegendaryCLI(core).uninstall_game(
|
|
|
|
LgndrUninstallGameArgs(
|
|
|
|
app_name=app_name,
|
|
|
|
keep_files=keep_files,
|
|
|
|
indirect_status=status,
|
|
|
|
yes=True,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
if not keep_config:
|
|
|
|
logger.info("Removing sections in config file")
|
|
|
|
config_helper.remove_section(app_name)
|
|
|
|
config_helper.remove_section(f"{app_name}.env")
|
|
|
|
|
|
|
|
config_helper.save_config()
|
|
|
|
|
|
|
|
return status.success, status.message
|
|
|
|
|
|
|
|
|
2021-11-02 10:53:04 +13:00
|
|
|
class GameUtils(QObject):
|
2021-11-17 10:54:23 +13:00
|
|
|
finished = pyqtSignal(str, str) # app_name, error
|
2021-11-02 10:53:04 +13:00
|
|
|
cloud_save_finished = pyqtSignal(str)
|
2023-01-11 03:32:29 +13:00
|
|
|
game_launched = pyqtSignal(RareGame)
|
2021-11-17 10:54:23 +13:00
|
|
|
update_list = pyqtSignal(str)
|
2021-11-02 10:53:04 +13:00
|
|
|
|
|
|
|
def __init__(self, parent=None):
|
|
|
|
super(GameUtils, self).__init__(parent=parent)
|
2022-02-26 06:43:27 +13:00
|
|
|
self.core = LegendaryCoreSingleton()
|
|
|
|
self.signals = GlobalSignalsSingleton()
|
|
|
|
self.args = ArgumentsSingleton()
|
2021-11-02 10:53:04 +13:00
|
|
|
|
2023-01-05 09:33:30 +13:00
|
|
|
self.running_games = {}
|
|
|
|
self.launch_queue = {}
|
|
|
|
|
2021-11-02 10:53:04 +13:00
|
|
|
self.cloud_save_utils = CloudSaveUtils()
|
|
|
|
self.cloud_save_utils.sync_finished.connect(self.sync_finished)
|
|
|
|
|
2023-01-05 09:33:30 +13:00
|
|
|
def check_running(self, rgame: RareGame):
|
|
|
|
if rgame.is_installed:
|
2023-01-11 03:32:29 +13:00
|
|
|
game_process = GameProcess(rgame, on_startup=True)
|
2022-06-09 07:55:54 +12:00
|
|
|
game_process.game_finished.connect(self.game_finished)
|
2022-06-12 02:59:53 +12:00
|
|
|
game_process.game_launched.connect(self.game_launched.emit)
|
2023-01-05 09:33:30 +13:00
|
|
|
self.running_games[rgame.app_name] = game_process
|
2022-06-09 07:55:54 +12:00
|
|
|
|
2023-01-10 06:58:57 +13:00
|
|
|
def uninstall_game(self, rgame: RareGame) -> bool:
|
2021-11-17 10:54:23 +13:00
|
|
|
# returns if uninstalled
|
2023-01-10 06:58:57 +13:00
|
|
|
if not os.path.exists(rgame.igame.install_path):
|
2021-12-24 22:09:50 +13:00
|
|
|
if QMessageBox.Yes == QMessageBox.question(
|
2022-01-03 10:52:43 +13:00
|
|
|
None,
|
2023-01-10 06:58:57 +13:00
|
|
|
self.tr("Uninstall - {}").format(rgame.igame.title),
|
2022-01-03 10:52:43 +13:00
|
|
|
self.tr(
|
|
|
|
"Game files of {} do not exist. Remove it from installed games?"
|
2023-01-10 06:58:57 +13:00
|
|
|
).format(rgame.igame.title),
|
2022-01-03 10:52:43 +13:00
|
|
|
QMessageBox.Yes | QMessageBox.No,
|
|
|
|
QMessageBox.Yes,
|
2021-12-24 22:09:50 +13:00
|
|
|
):
|
2023-01-10 06:58:57 +13:00
|
|
|
self.core.lgd.remove_installed_game(rgame.app_name)
|
2021-11-17 10:54:23 +13:00
|
|
|
return True
|
|
|
|
else:
|
|
|
|
return False
|
|
|
|
|
2023-01-10 06:58:57 +13:00
|
|
|
proceed, keep_files, keep_config = UninstallDialog(rgame.game).get_options()
|
2022-07-16 06:16:12 +12:00
|
|
|
if not proceed:
|
2021-11-02 10:53:04 +13:00
|
|
|
return False
|
2023-01-10 06:58:57 +13:00
|
|
|
success, message = uninstall_game(self.core, rgame.app_name, keep_files, keep_config)
|
2022-07-24 10:06:35 +12:00
|
|
|
if not success:
|
2023-01-10 06:58:57 +13:00
|
|
|
QMessageBox.warning(None, self.tr("Uninstall - {}").format(rgame.title), message, QMessageBox.Close)
|
|
|
|
self.signals.game.uninstalled.emit(rgame.app_name)
|
2021-11-02 10:53:04 +13:00
|
|
|
return True
|
|
|
|
|
2021-12-24 22:09:50 +13:00
|
|
|
def prepare_launch(
|
2023-01-05 09:33:30 +13:00
|
|
|
self, rgame: RareGame, offline: bool = False, skip_update_check: bool = False
|
2021-12-24 22:09:50 +13:00
|
|
|
):
|
2021-11-17 10:54:23 +13:00
|
|
|
dont_sync_after_finish = False
|
|
|
|
|
2022-06-12 02:59:53 +12:00
|
|
|
# TODO move this to helper
|
2023-01-05 09:33:30 +13:00
|
|
|
if rgame.game.supports_cloud_saves and not offline:
|
2021-11-17 10:54:23 +13:00
|
|
|
try:
|
2023-01-10 06:58:57 +13:00
|
|
|
sync = self.cloud_save_utils.sync_before_launch_game(rgame)
|
2021-11-17 10:54:23 +13:00
|
|
|
except ValueError:
|
|
|
|
logger.info("Cancel startup")
|
2023-01-10 06:58:57 +13:00
|
|
|
self.sync_finished(rgame)
|
2022-03-23 08:40:23 +13:00
|
|
|
return
|
2021-11-17 10:54:23 +13:00
|
|
|
except AssertionError:
|
|
|
|
dont_sync_after_finish = True
|
|
|
|
else:
|
|
|
|
if sync:
|
2023-01-10 06:58:57 +13:00
|
|
|
self.launch_queue[rgame.app_name] = (rgame, skip_update_check, offline)
|
2021-11-17 10:54:23 +13:00
|
|
|
return
|
2023-01-10 06:58:57 +13:00
|
|
|
self.sync_finished(rgame)
|
2021-11-14 11:56:07 +13:00
|
|
|
|
2021-12-24 22:09:50 +13:00
|
|
|
self.launch_game(
|
2023-01-05 09:33:30 +13:00
|
|
|
rgame, offline, skip_update_check, ask_always_sync=dont_sync_after_finish
|
2021-12-24 22:09:50 +13:00
|
|
|
)
|
|
|
|
|
|
|
|
def launch_game(
|
2022-01-03 10:52:43 +13:00
|
|
|
self,
|
2023-01-05 09:33:30 +13:00
|
|
|
rgame: RareGame,
|
2022-01-03 10:52:43 +13:00
|
|
|
offline: bool = False,
|
|
|
|
skip_update_check: bool = False,
|
|
|
|
wine_bin: str = None,
|
|
|
|
wine_pfx: str = None,
|
|
|
|
ask_always_sync: bool = False,
|
2021-12-24 22:09:50 +13:00
|
|
|
):
|
2022-07-30 18:02:08 +12:00
|
|
|
executable = misc.get_rare_executable()
|
2022-05-19 09:41:48 +12:00
|
|
|
executable, args = executable[0], executable[1:]
|
2022-05-15 11:25:13 +12:00
|
|
|
args.extend([
|
2023-01-05 09:33:30 +13:00
|
|
|
"start", rgame.app_name
|
2022-05-15 11:25:13 +12:00
|
|
|
])
|
2022-05-19 09:41:48 +12:00
|
|
|
if offline:
|
|
|
|
args.append("--offline")
|
|
|
|
if skip_update_check:
|
|
|
|
args.append("--skip-update-check")
|
|
|
|
if wine_bin:
|
|
|
|
args.extend(["--wine-bin", wine_bin])
|
|
|
|
if wine_pfx:
|
|
|
|
args.extend(["--wine-prefix", wine_pfx])
|
|
|
|
if ask_always_sync:
|
|
|
|
args.extend("--ask-always-sync")
|
|
|
|
|
2022-06-12 02:59:53 +12:00
|
|
|
# kill me, if I don't change it before commit
|
2022-05-19 09:41:48 +12:00
|
|
|
QProcess.startDetached(executable, args)
|
|
|
|
logger.info(f"Start new Process: ({executable} {' '.join(args)})")
|
2023-01-05 09:33:30 +13:00
|
|
|
game_process = GameProcess(rgame, ask_always_sync)
|
2022-05-15 11:25:13 +12:00
|
|
|
game_process.game_finished.connect(self.game_finished)
|
2022-06-12 02:59:53 +12:00
|
|
|
game_process.game_launched.connect(self.game_launched.emit)
|
2023-01-05 09:33:30 +13:00
|
|
|
self.running_games[rgame.app_name] = game_process
|
2021-11-02 10:53:04 +13:00
|
|
|
|
2023-01-11 08:40:57 +13:00
|
|
|
@pyqtSlot(RareGame, int)
|
2023-01-10 06:58:57 +13:00
|
|
|
def game_finished(self, rgame: RareGame, exit_code):
|
|
|
|
if self.running_games.get(rgame.app_name):
|
|
|
|
self.running_games.pop(rgame.app_name)
|
2022-06-24 08:01:14 +12:00
|
|
|
if exit_code == -1234:
|
|
|
|
return
|
|
|
|
|
2023-01-10 06:58:57 +13:00
|
|
|
self.finished.emit(rgame.app_name, "")
|
2023-01-11 09:31:10 +13:00
|
|
|
rgame.signals.game.finished.emit()
|
2022-06-24 08:01:14 +12:00
|
|
|
|
2022-02-02 10:29:34 +13:00
|
|
|
logger.info(f"Game exited with exit code: {exit_code}")
|
2022-12-29 06:55:15 +13:00
|
|
|
self.signals.discord_rpc.set_title.emit("")
|
2023-01-10 06:58:57 +13:00
|
|
|
if exit_code == 1 and rgame.is_origin:
|
2021-11-02 10:53:04 +13:00
|
|
|
msg_box = QMessageBox()
|
2021-12-24 22:09:50 +13:00
|
|
|
msg_box.setText(
|
|
|
|
self.tr(
|
|
|
|
"Origin is not installed. Do you want to download installer file? "
|
|
|
|
)
|
|
|
|
)
|
2021-11-02 10:53:04 +13:00
|
|
|
msg_box.addButton(QPushButton("Download"), QMessageBox.YesRole)
|
|
|
|
msg_box.addButton(QPushButton("Cancel"), QMessageBox.RejectRole)
|
|
|
|
resp = msg_box.exec()
|
|
|
|
# click install button
|
|
|
|
if resp == 0:
|
2022-03-28 10:03:48 +13:00
|
|
|
QDesktopServices.openUrl(QUrl("https://www.dm.origin.com/download"))
|
|
|
|
return
|
2022-06-24 08:01:14 +12:00
|
|
|
|
2022-03-10 09:45:02 +13:00
|
|
|
if exit_code != 0:
|
2022-08-01 11:22:37 +12:00
|
|
|
pass
|
|
|
|
"""
|
2021-12-24 22:09:50 +13:00
|
|
|
QMessageBox.warning(
|
|
|
|
None,
|
|
|
|
"Warning",
|
2022-03-10 09:45:02 +13:00
|
|
|
self.tr("Failed to launch {}. Check logs to find error").format(
|
2021-12-24 22:09:50 +13:00
|
|
|
self.core.get_game(app_name).app_title
|
|
|
|
),
|
|
|
|
)
|
2022-08-01 11:22:37 +12:00
|
|
|
"""
|
2021-11-02 10:53:04 +13:00
|
|
|
|
2023-01-10 06:58:57 +13:00
|
|
|
if rgame.app_name in self.running_games.keys():
|
|
|
|
self.running_games.pop(rgame.app_name)
|
2021-11-02 10:53:04 +13:00
|
|
|
|
2023-01-10 06:58:57 +13:00
|
|
|
if rgame.game.supports_cloud_saves:
|
2021-11-02 10:53:04 +13:00
|
|
|
if exit_code != 0:
|
2021-12-24 22:09:50 +13:00
|
|
|
r = QMessageBox.question(
|
|
|
|
None,
|
|
|
|
"Question",
|
|
|
|
self.tr(
|
2022-03-29 08:11:22 +13:00
|
|
|
"Game exited with code {}, which is not a normal code. "
|
|
|
|
"It could be caused by a crash. Do you want to sync cloud saves"
|
2021-12-24 22:09:50 +13:00
|
|
|
).format(exit_code),
|
|
|
|
buttons=QMessageBox.Yes | QMessageBox.No,
|
|
|
|
defaultButton=QMessageBox.Yes,
|
|
|
|
)
|
2021-11-02 10:53:04 +13:00
|
|
|
if r != QMessageBox.Yes:
|
|
|
|
return
|
2022-06-24 08:01:14 +12:00
|
|
|
|
|
|
|
# TODO move this to helper
|
2023-01-10 06:58:57 +13:00
|
|
|
self.cloud_save_utils.game_finished(rgame, always_ask=False)
|
|
|
|
|
|
|
|
@pyqtSlot(RareGame)
|
|
|
|
def sync_finished(self, rgame: RareGame):
|
|
|
|
if rgame.app_name in self.launch_queue.keys():
|
|
|
|
self.cloud_save_finished.emit(rgame.app_name)
|
|
|
|
params = self.launch_queue[rgame.app_name]
|
|
|
|
self.launch_queue.pop(rgame.app_name)
|
2021-11-02 10:53:04 +13:00
|
|
|
self.launch_game(*params)
|
|
|
|
else:
|
2023-01-10 06:58:57 +13:00
|
|
|
self.cloud_save_finished.emit(rgame.app_name)
|