Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 53 additions & 40 deletions rare/commands/launcher/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
from PySide6.QtWidgets import QApplication

from rare.lgndr.core import LegendaryCore
from rare.models.base_game import RareGameSlim
from rare.models.game_slim import RareGameSlim
from rare.models.launcher import Actions, BaseModel, ErrorModel, FinishedModel, StateChangedModel
from rare.shared.workers.cloud_sync import CloudSyncWorker
from rare.utils.paths import get_rare_executable
Expand All @@ -50,16 +50,18 @@
}


class PreLaunchSignals(QObject):
ready_to_launch = Signal(LaunchParams)
pre_launch_command_started = Signal()
pre_launch_command_finished = Signal(int) # exit_code
error_occurred = Signal(str)


class PreLaunch(QRunnable):
class Signals(QObject):
ready_to_launch = Signal(LaunchParams)
pre_launch_command_started = Signal()
pre_launch_command_finished = Signal(int) # exit_code
error_occurred = Signal(str)

def __init__(self, args: InitParams, rgame: RareGameSlim, sync_action=None):
super(PreLaunch, self).__init__()
self.signals = self.Signals()
self.signals = PreLaunchSignals()
self.logger = getLogger(type(self).__name__)
self.args = args
self.rgame = rgame
Expand All @@ -76,8 +78,8 @@ def run(self) -> None:

if args := self.prepare_launch(self.args):
self.signals.ready_to_launch.emit(args)
else:
return
self.signals.disconnect(self.signals)
self.signals.deleteLater()

def prepare_launch(self, args: InitParams) -> Optional[LaunchParams]:
try:
Expand All @@ -92,7 +94,8 @@ def prepare_launch(self, args: InitParams) -> Optional[LaunchParams]:
proc = get_configured_qprocess(shlex.split(launch.pre_launch_command), launch.environment)
proc.setProcessChannelMode(QProcess.ProcessChannelMode.MergedChannels)
proc.readyReadStandardOutput.connect(
lambda: self.logger.info(str(proc.readAllStandardOutput().data(), "utf-8", "ignore"))
(lambda obj: obj.logger.debug(
str(proc.readAllStandardOutput().data(), "utf-8", "ignore"))).__get__(self)
)
self.signals.pre_launch_command_started.emit()
self.logger.info("Running pre-launch command %s, %s", proc.program(), proc.arguments())
Expand All @@ -102,17 +105,20 @@ def prepare_launch(self, args: InitParams) -> Optional[LaunchParams]:
proc.waitForFinished(-1)
else:
proc.startDetached()

return launch


class SyncCheckWorkerSignals(QObject):
sync_state_ready = Signal()
error_occurred = Signal(str)


class SyncCheckWorker(QRunnable):
class Signals(QObject):
sync_state_ready = Signal()
error_occurred = Signal(str)

def __init__(self, core: LegendaryCore, rgame: RareGameSlim):
super().__init__()
self.signals = self.Signals()
self.signals = SyncCheckWorkerSignals()
self.core = core
self.rgame = rgame

Expand All @@ -123,6 +129,8 @@ def run(self) -> None:
self.signals.error_occurred.emit(str(e))
return
self.signals.sync_state_ready.emit()
self.signals.disconnect(self.signals)
self.signals.deleteLater()


class RareLauncherException(RareAppException):
Expand Down Expand Up @@ -171,26 +179,17 @@ def __init__(self, args: InitParams):
if args.show_console:
self.console = ConsoleDialog(game.app_title)
self.console.show()
self.game_process.stateChanged.connect(
lambda s: self.console.kill_button.setEnabled(
self.game_process.state() == QProcess.ProcessState.Running
)
)
self.game_process.stateChanged.connect(
lambda s: self.console.terminate_button.setEnabled(
self.game_process.state() == QProcess.ProcessState.Running
)
)
self.game_process.stateChanged.connect(self._on_game_process_changed)

self.sync_dialog: Optional[CloudSyncDialog] = None

self.game_process.finished.connect(self.__process_finished)
self.game_process.errorOccurred.connect(self.__process_errored)
if self.console:
self.game_process.readyReadStandardOutput.connect(self.__proc_log_stdout)
self.game_process.readyReadStandardError.connect(self.__proc_log_stderr)
self.console.term.connect(self.__proc_term)
self.console.kill.connect(self.__proc_kill)
self.game_process.readyReadStandardOutput.connect(self._proc_log_stdout)
self.game_process.readyReadStandardError.connect(self._proc_log_stderr)
self.console.term.connect(self._proc_term)
self.console.kill.connect(self._proc_kill)

ret = self.server.listen(f"rare_{args.app_name}")
if not ret:
Expand All @@ -207,23 +206,28 @@ def __init__(self, args: InitParams):
# The timer's signal will be serviced once we call `exec()` on the application
QTimer.singleShot(0, self.start)

@Slot(QProcess.ProcessState)
def _on_game_process_changed(self, state: QProcess.ProcessState):
self.console.kill_button.setEnabled(state == QProcess.ProcessState.Running)
self.console.terminate_button.setEnabled(state == QProcess.ProcessState.Running)

@Slot()
def __proc_log_stdout(self):
def _proc_log_stdout(self):
self.console.log_stdout(self.game_process.readAllStandardOutput().data().decode("utf-8", "ignore"))

@Slot()
def __proc_log_stderr(self):
def _proc_log_stderr(self):
self.console.log_stderr(self.game_process.readAllStandardError().data().decode("utf-8", "ignore"))

@Slot()
def __proc_term(self):
def _proc_term(self):
if platform.system() == "Windows":
self.game_process.terminate()
else:
os.kill(self.game_process.processId(), signal.SIGINT)

@Slot()
def __proc_kill(self):
def _proc_kill(self):
if platform.system() == "Windows":
self.game_process.kill()
else:
Expand Down Expand Up @@ -251,23 +255,32 @@ def send_message(self, message: BaseModel):
else:
self.logger.error("Can't send message")

def check_saves_finished(self, exit_code: int):
self.rgame.signals.widget.update.connect(lambda: self.on_exit(exit_code))
def check_saves(self, exit_code: int):
# self.rgame.signals.widget.refresh.connect(lambda: self.on_exit(exit_code))
self.rgame.signals.widget.refresh.connect(
(lambda obj: obj.on_exit(exit_code)).__get__(self)
)

state, (dt_local, dt_remote) = self.rgame.save_game_state

if state == SaveGameStatus.LOCAL_NEWER and not self.no_sync_on_exit:
action = CloudSyncDialogResult.UPLOAD
self.__check_saves_finished(exit_code, action)
self.check_saves_finished(exit_code, action)
else:
self.sync_dialog = CloudSyncDialog(self.rgame.igame, dt_local, dt_remote)
self.sync_dialog.result_ready.connect(lambda a: self.__check_saves_finished(exit_code, a))
# self.sync_dialog.result_ready.connect(
# lambda a: self.__check_saves_finished(exit_code, a)
# )
self.sync_dialog.result_ready.connect(
(lambda obj, a: obj.check_saves_finished(exit_code, a)).__get__(self)
)
self.sync_dialog.open()

@Slot(int, int)
@Slot(int, CloudSyncDialogResult)
def __check_saves_finished(self, exit_code, action):
def check_saves_finished(self, exit_code, action):
if self.sync_dialog is not None:
self.sync_dialog.disconnect(self.sync_dialog)
self.sync_dialog.deleteLater()
self.sync_dialog = None
action = CloudSyncDialogResult(action)
Expand All @@ -291,7 +304,7 @@ def __process_finished(self, exit_code: int, exit_status: QProcess.ExitStatus):
self.logger.info("Game finished")

if self.rgame.auto_sync_saves:
self.check_saves_finished(exit_code)
self.check_saves(exit_code)
else:
self.on_exit(exit_code)

Expand Down Expand Up @@ -482,9 +495,9 @@ def stop(self, sig: int = signal.SIGINT):
if shiboken6.isValid(self.game_process): # pylint: disable=E1101
if self.game_process.state() != QProcess.ProcessState.NotRunning:
if sig == signal.SIGTERM:
self.__proc_term()
self._proc_term()
elif sig == signal.SIGINT:
self.__proc_kill()
self._proc_kill()
self.game_process.waitForFinished()
exit_code = self.game_process.exitCode()
self.game_process.deleteLater()
Expand Down
4 changes: 2 additions & 2 deletions rare/commands/launcher/console_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,13 @@ def __init__(self, app_title: str, parent=None):
self.terminate_button = QPushButton(self.tr("Terminate"))
# self.terminate_button.setVisible(platform.system() == "Windows")
button_layout.addWidget(self.terminate_button)
self.terminate_button.clicked.connect(lambda: self.term.emit())
self.terminate_button.clicked.connect(self.term)
self.terminate_button.setEnabled(False)

self.kill_button = QPushButton(self.tr("Kill"))
# self.kill_button.setVisible(platform.system() == "Windows")
button_layout.addWidget(self.kill_button)
self.kill_button.clicked.connect(lambda: self.kill.emit())
self.kill_button.clicked.connect(self.kill)
self.kill_button.setEnabled(False)

layout.addLayout(button_layout)
Expand Down
2 changes: 1 addition & 1 deletion rare/commands/launcher/lgd_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from legendary.models.game import LaunchParameters
from PySide6.QtCore import QProcess, QProcessEnvironment

from rare.models.base_game import RareGameSlim
from rare.models.game_slim import RareGameSlim
from rare.utils.paths import setup_compat_shaders_dir

logger = getLogger("RareLauncherUtils")
Expand Down
39 changes: 25 additions & 14 deletions rare/components/dialogs/install/dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def __init__(self, settings: RareAppSettings, rgame: "RareGame", options: Instal
self.__queue_item: Optional[InstallQueueItemModel] = None

self.selectable = InstallDialogSelective(rgame, parent=self)
self.selectable.stateChanged.connect(self.__on_option_changed)
self.selectable.stateChanged.connect(self._on_option_changed)
self.ui.main_layout.insertRow(
self.ui.main_layout.getWidgetPosition(self.ui.shortcut_label)[0] + 1,
# self.tr("Optional"),
Expand Down Expand Up @@ -102,13 +102,13 @@ def __init__(self, settings: RareAppSettings, rgame: "RareGame", options: Instal
self.ui.shortcut_label.setDisabled(rgame.is_installed or rgame.is_dlc)
self.ui.shortcut_check.setDisabled(rgame.is_installed or rgame.is_dlc)
self.ui.shortcut_check.setChecked(not rgame.is_installed and self.settings.get_value(app_settings.create_shortcut))
self.ui.shortcut_check.checkStateChanged.connect(self.__on_option_changed_no_reload)
self.ui.shortcut_check.checkStateChanged.connect(self._on_option_changed_no_reload)

self.set_error_labels()

self.ui.platform_combo.addItems(reversed(rgame.platforms))
self.ui.platform_combo.setCurrentIndex(self.ui.platform_combo.findText(options.platform))
self.ui.platform_combo.currentIndexChanged.connect(self.__on_option_changed)
self.ui.platform_combo.currentIndexChanged.connect(self._on_option_changed)
self.ui.platform_combo.currentIndexChanged.connect(self.check_incompatible_platform)
self.ui.platform_combo.currentIndexChanged.connect(self.reset_install_dir)
self.ui.platform_combo.currentTextChanged.connect(self.selectable.update_list)
Expand All @@ -122,17 +122,28 @@ def __init__(self, settings: RareAppSettings, rgame: "RareGame", options: Instal
self.selectable.click()

self.advanced.ui.max_workers_spin.setValue(self.core.lgd.config.getint("Legendary", "max_workers", fallback=0))
self.advanced.ui.max_workers_spin.valueChanged.connect(self.__on_option_changed)
self.advanced.ui.max_workers_spin.valueChanged.connect(self._on_option_changed)

self.advanced.ui.max_memory_spin.setValue(self.core.lgd.config.getint("Legendary", "max_memory", fallback=0))
self.advanced.ui.max_memory_spin.valueChanged.connect(self.__on_option_changed)
self.advanced.ui.max_memory_spin.valueChanged.connect(self._on_option_changed)

self.advanced.ui.read_files_check.checkStateChanged.connect(self.__on_option_changed)
self.advanced.ui.use_signed_urls_check.checkStateChanged.connect(self.__on_option_changed)
self.advanced.ui.dl_optimizations_check.checkStateChanged.connect(self.__on_option_changed)
self.advanced.ui.force_download_check.checkStateChanged.connect(self.__on_option_changed)
self.advanced.ui.ignore_space_check.checkStateChanged.connect(self.__on_option_changed)
self.advanced.ui.download_only_check.checkStateChanged.connect(self.__on_option_changed_no_reload)
self.advanced.ui.read_files_check.setChecked(options.read_files)
self.advanced.ui.read_files_check.checkStateChanged.connect(self._on_option_changed)

self.advanced.ui.use_signed_urls_check.setChecked(options.always_use_signed_urls)
self.advanced.ui.use_signed_urls_check.checkStateChanged.connect(self._on_option_changed)

self.advanced.ui.dl_optimizations_check.setChecked(options.order_opt)
self.advanced.ui.dl_optimizations_check.checkStateChanged.connect(self._on_option_changed)

self.advanced.ui.force_download_check.setChecked(options.force)
self.advanced.ui.force_download_check.checkStateChanged.connect(self._on_option_changed)

self.advanced.ui.ignore_space_check.setChecked(options.ignore_space)
self.advanced.ui.ignore_space_check.checkStateChanged.connect(self._on_option_changed)

self.advanced.ui.download_only_check.setChecked(options.no_install)
self.advanced.ui.download_only_check.checkStateChanged.connect(self._on_option_changed_no_reload)

self.reset_install_dir(self.ui.platform_combo.currentIndex())
self.selectable.update_list(self.ui.platform_combo.currentText())
Expand All @@ -159,7 +170,7 @@ def __init__(self, settings: RareAppSettings, rgame: "RareGame", options: Instal

self.advanced.ui.install_prereqs_label.setEnabled(False)
self.advanced.ui.install_prereqs_check.setEnabled(False)
self.advanced.ui.install_prereqs_check.checkStateChanged.connect(self.__on_option_changed_no_reload)
self.advanced.ui.install_prereqs_check.checkStateChanged.connect(self._on_option_changed_no_reload)
self.advanced.ui.install_prereqs_check.setChecked(self.__options.install_prereqs)

# lk: set object names for CSS properties
Expand Down Expand Up @@ -241,13 +252,13 @@ def action_handler(self):
self.get_download_info()

@Slot()
def __on_option_changed(self):
def _on_option_changed(self):
self.options_changed = True
self.accept_button.setEnabled(False)
self.action_button.setEnabled(not self.active())

@Slot(Qt.CheckState)
def __on_option_changed_no_reload(self, state: Qt.CheckState):
def _on_option_changed_no_reload(self, state: Qt.CheckState):
if self.sender() is self.advanced.ui.download_only_check:
self.__options.no_install = state != Qt.CheckState.Unchecked
elif self.sender() is self.ui.shortcut_check:
Expand Down
1 change: 1 addition & 0 deletions rare/components/dialogs/install/selective.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ def __init__(self, rgame: RareGame, parent=None):

def update_list(self, platform: str):
if self.widget is not None:
self.widget.disconnect(self.widget)
self.widget.deleteLater()
self.widget = SelectiveWidget(self.rgame, platform, parent=self)
self.widget.stateChanged.connect(self.stateChanged)
Expand Down
Loading