1
0
Fork 0
mirror of synced 2024-07-02 21:20:54 +12:00
Rare/rare/components/tabs/games/game_list.py

411 lines
17 KiB
Python
Raw Normal View History

from logging import getLogger
2021-04-13 02:02:16 +12:00
import psutil
from PyQt5.QtCore import Qt, pyqtSignal, QSettings, QTimer
2021-05-18 06:22:29 +12:00
from PyQt5.QtWidgets import QScrollArea, QWidget, QLabel, QVBoxLayout, QStackedWidget
2021-02-10 23:48:25 +13:00
from legendary.core import LegendaryCore
from rare import data_dir
2021-05-18 06:22:29 +12:00
from rare.components.tabs.games.game_widgets.base_installed_widget import BaseInstalledWidget
2021-04-08 08:42:30 +12:00
from rare.components.tabs.games.game_widgets.installed_icon_widget import GameWidgetInstalled
from rare.components.tabs.games.game_widgets.installed_list_widget import InstalledListWidget
from rare.components.tabs.games.game_widgets.installing_game_widget import InstallingGameWidget
2021-04-08 08:42:30 +12:00
from rare.components.tabs.games.game_widgets.uninstalled_icon_widget import IconWidgetUninstalled
from rare.components.tabs.games.game_widgets.uninstalled_list_widget import ListWidgetUninstalled
2021-04-08 08:39:23 +12:00
from rare.utils.extra_widgets import FlowLayout
from rare.utils.models import InstallOptionsModel
2021-08-17 09:08:15 +12:00
from rare.utils.utils import download_image, get_uninstalled_pixmap, get_pixmap
2021-02-10 23:48:25 +13:00
logger = getLogger("Game list")
2021-02-10 23:48:25 +13:00
class GameList(QStackedWidget):
install_game = pyqtSignal(InstallOptionsModel)
2021-02-23 06:50:00 +13:00
show_game_info = pyqtSignal(str)
2021-03-09 05:20:28 +13:00
update_game = pyqtSignal()
2021-04-12 08:44:18 +12:00
game_exited = pyqtSignal(str)
game_started = pyqtSignal(str)
show_uninstalled_info = pyqtSignal(str)
2021-03-09 08:36:42 +13:00
2021-04-13 07:55:08 +12:00
running_games = []
2021-04-13 02:02:16 +12:00
active_game = ("", 0)
2021-04-20 01:44:28 +12:00
def __init__(self, core: LegendaryCore, parent, offline):
super(GameList, self).__init__(parent=parent)
2021-02-10 23:48:25 +13:00
self.core = core
2021-02-18 05:46:03 +13:00
self.setObjectName("list_widget")
2021-04-20 01:44:28 +12:00
self.offline = offline
2021-09-03 09:32:25 +12:00
self.installing_widget = InstallingGameWidget()
2021-03-09 03:07:07 +13:00
self.settings = QSettings()
icon_view = self.settings.value("icon_view", True, bool)
2021-06-21 07:10:55 +12:00
self.procs = []
for proc in psutil.process_iter():
try:
self.procs.append((proc.name(), proc.pid))
except psutil.ZombieProcess:
continue
except psutil.NoSuchProcess:
continue
except Exception:
continue
2021-03-09 03:07:07 +13:00
self.init_ui(icon_view)
def init_ui(self, icon_view=True):
self.icon_scrollarea = QScrollArea(parent=self)
self.icon_widget = QWidget(parent=self.icon_scrollarea)
self.list_scrollarea = QScrollArea(parent=self)
self.list_widget = QWidget(parent=self.list_scrollarea)
self.icon_scrollarea.setWidgetResizable(True)
self.icon_scrollarea.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
2021-03-09 03:07:07 +13:00
2021-04-06 23:41:52 +12:00
self.list_scrollarea.setWidgetResizable(True)
self.list_scrollarea.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
self.info_text = self.tr("Installed Games: {} Available Games: {}").format(
len(self.core.get_installed_list()),
len(self.core.get_game_list(update_assets=True)))
self.icon_parent_layout = QVBoxLayout()
self.icon_parent_layout.addWidget(QLabel(self.info_text))
2021-04-06 03:45:20 +12:00
self.icon_layout = FlowLayout()
self.list_layout = QVBoxLayout()
self.list_layout.addWidget(QLabel(self.info_text))
self.updates = []
self.widgets = {}
2021-06-12 10:29:55 +12:00
if not self.offline:
self.bit32 = [i.app_name for i in self.core.get_game_and_dlc_list(True, "Win32")[0]]
self.mac_games = [i.app_name for i in self.core.get_game_and_dlc_list(True, "Mac")[0]]
2021-09-02 05:41:01 +12:00
self.no_assets = [i.app_name for i in self.core.get_non_asset_library_items()[0]]
2021-06-12 10:29:55 +12:00
else:
self.bit32 = []
self.mac_games = []
2021-04-22 08:34:48 +12:00
self.installed = sorted(self.core.get_installed_list(), key=lambda x: x.title)
2021-09-03 09:32:25 +12:00
self.installing_widget = InstallingGameWidget()
self.icon_layout.addWidget(self.installing_widget)
self.installing_widget.setVisible(False)
2021-02-18 05:46:03 +13:00
# Installed Games
2021-04-22 08:34:48 +12:00
for igame in self.installed:
2021-05-18 06:22:29 +12:00
icon_widget, list_widget = self.add_installed_widget(igame)
self.icon_layout.addWidget(icon_widget)
self.list_layout.addWidget(list_widget)
2021-06-12 10:29:55 +12:00
if not self.offline:
self.uninstalled_games = []
installed = [i.app_name for i in self.core.get_installed_list()]
# get Uninstalled games
games, self.dlcs = self.core.get_game_and_dlc_list(update_assets=not self.offline)
2021-09-02 05:41:01 +12:00
for game in games:
2021-06-12 10:29:55 +12:00
if not game.app_name in installed:
self.uninstalled_games.append(game)
# add uninstalled games
2021-09-02 05:41:01 +12:00
self.uninstalled_games += self.core.get_non_asset_library_items()[0]
for game in sorted(self.uninstalled_games, key=lambda x: x.app_title):
2021-06-12 10:29:55 +12:00
icon_widget, list_widget = self.add_uninstalled_widget(game)
self.icon_layout.addWidget(icon_widget)
self.list_layout.addWidget(list_widget)
else:
self.dlcs = []
self.icon_parent_layout.addLayout(self.icon_layout)
2021-04-06 03:45:20 +12:00
self.icon_parent_layout.addStretch(1)
2021-03-26 02:15:18 +13:00
self.list_layout.addStretch(1)
self.icon_widget.setLayout(self.icon_parent_layout)
self.list_widget.setLayout(self.list_layout)
self.icon_scrollarea.setWidget(self.icon_widget)
self.list_scrollarea.setWidget(self.list_widget)
self.addWidget(self.icon_scrollarea)
self.addWidget(self.list_scrollarea)
if not icon_view:
self.setCurrentIndex(1)
2021-05-12 21:06:31 +12:00
if filter_games := self.settings.value("filter", "", str):
self.filter(filter_games)
2021-03-26 02:15:18 +13:00
def start_download(self, app_name):
self.installing_widget.set_game(self.core.get_game(app_name))
self.installing_widget.setVisible(True)
2021-05-18 06:22:29 +12:00
def add_uninstalled_widget(self, game):
2021-08-17 09:08:15 +12:00
pixmap = get_uninstalled_pixmap(game.app_name)
if pixmap.isNull():
logger.info(game.app_title + " has a corrupt image. Reloading...")
2021-05-18 06:22:29 +12:00
download_image(game, force=True)
2021-08-17 09:08:15 +12:00
pixmap = get_uninstalled_pixmap(game.app_name)
2021-05-18 06:22:29 +12:00
icon_widget = IconWidgetUninstalled(game, self.core, pixmap)
icon_widget.show_uninstalled_info.connect(self.show_install_info)
2021-05-18 06:22:29 +12:00
list_widget = ListWidgetUninstalled(self.core, game, pixmap)
list_widget.show_uninstalled_info.connect(self.show_install_info)
2021-05-18 06:22:29 +12:00
self.widgets[game.app_name] = (icon_widget, list_widget)
return icon_widget, list_widget
def add_installed_widget(self, igame):
2021-08-17 09:08:15 +12:00
pixmap = get_pixmap(igame.app_name)
2021-05-18 06:22:29 +12:00
if pixmap.isNull():
logger.info(igame.title + " has a corrupt image.")
2021-08-17 08:50:31 +12:00
download_image(self.core.get_game(igame.app_name), force=True)
2021-08-17 09:08:15 +12:00
pixmap = get_pixmap(igame.app_name)
2021-05-18 06:22:29 +12:00
icon_widget = GameWidgetInstalled(igame, self.core, pixmap, self.offline)
# self.icon_layout.addWidget(icon_widget)
list_widget = InstalledListWidget(igame, self.core, pixmap, self.offline)
# self.list_layout.addWidget(list_widget)
self.widgets[igame.app_name] = (icon_widget, list_widget)
icon_widget.show_info.connect(self.show_game_info.emit)
list_widget.show_info.connect(self.show_game_info.emit)
icon_widget.launch_signal.connect(self.launch)
icon_widget.finish_signal.connect(self.finished)
icon_widget.update_list.connect(self.update_list)
list_widget.launch_signal.connect(self.launch)
list_widget.finish_signal.connect(self.finished)
list_widget.update_list.connect(self.update_list)
if icon_widget.update_available:
self.updates.append(igame)
active, pid = self.check_for_active_game(igame)
if active:
# Only one game works: Workaround for Satisfactory EA and Exp.
self.launch(igame.app_name)
icon_widget.game_running = True
list_widget.game_running = True
self.active_game = (igame.app_name, pid)
self.timer = QTimer()
self.timer.timeout.connect(self.is_finished)
self.timer.start(10000)
return icon_widget, list_widget
2021-03-26 02:15:18 +13:00
2021-04-13 02:02:16 +12:00
def is_finished(self):
if psutil.pid_exists(self.active_game[1]):
self.timer.start(10000)
else:
self.finished(self.active_game[0])
del self.timer
def check_for_active_game(self, igame):
executable = igame.executable.split("/")[-1].split("\\")[-1]
if executable.endswith(".exe"):
2021-04-14 04:01:25 +12:00
executable = executable[:-4] # remove .exe
2021-04-13 02:02:16 +12:00
for i, pid in self.procs:
if executable in i:
# Workaround for Satisfactory: Check Cmdline args
2021-04-13 02:02:16 +12:00
if igame.app_name in ["CrabEA", "CrabTest"]:
p = psutil.Process(pid)
if not igame.install_path.split("/")[-1].split("\\")[-1] in " ".join(p.cmdline()):
return False, 0
return True, pid
return False, 0
def show_install_info(self, app_name):
2021-05-12 03:29:35 +12:00
self.show_uninstalled_info.emit(app_name)
2021-03-27 00:50:57 +13:00
def finished(self, app_name):
2021-04-13 07:55:08 +12:00
self.running_games.remove(app_name)
2021-04-13 02:02:16 +12:00
self.active_game = ("", 0)
2021-03-27 00:50:57 +13:00
self.widgets[app_name][0].info_text = ""
self.widgets[app_name][0].info_label.setText("")
self.widgets[app_name][1].launch_button.setDisabled(False)
self.widgets[app_name][1].launch_button.setText(self.tr("Launch"))
2021-04-10 21:27:40 +12:00
if self.widgets[app_name][0].game.supports_cloud_saves:
if not self.settings.value(f"{app_name}/auto_sync_cloud", True, bool) \
and not self.settings.value("auto_sync_cloud", True, bool):
logger.info("Auto saves disabled")
return
self.widgets[app_name][0].info_text = self.tr("Sync CLoud saves")
self.widgets[app_name][0].info_label.setText(self.tr("Sync CLoud saves"))
self.widgets[app_name][1].info_label.setText(self.tr("Sync CLoud saves"))
2021-04-13 22:38:11 +12:00
self.game_exited.emit(app_name)
2021-03-27 00:50:57 +13:00
def launch(self, app_name):
2021-04-13 07:55:08 +12:00
self.running_games.append(app_name)
2021-04-13 22:38:11 +12:00
self.game_started.emit(app_name)
self.widgets[app_name][0].info_text = self.tr("Game running")
2021-04-13 02:02:16 +12:00
self.widgets[app_name][0].info_label.setText(self.tr("Game running"))
self.widgets[app_name][1].launch_button.setDisabled(True)
self.widgets[app_name][1].launch_button.setText(self.tr("Game running"))
2021-02-10 23:48:25 +13:00
def search(self, text: str):
for t in self.widgets.values():
for w in t:
2021-03-26 00:14:34 +13:00
if text.lower() in w.game.app_title.lower() + w.game.app_name.lower():
w.setVisible(True)
else:
w.setVisible(False)
def filter(self, filter="installed"):
for t in self.widgets.values():
for w in t:
if filter == "installed":
w.setVisible(self.core.is_installed(w.game.app_name))
elif filter == "offline":
if self.core.is_installed(w.game.app_name):
w.setVisible(w.igame.can_run_offline)
else:
w.setVisible(False)
2021-06-12 10:29:55 +12:00
elif filter == "32bit" and self.bit32:
2021-05-12 21:06:31 +12:00
w.setVisible(w.game.app_name in self.bit32)
elif filter == "mac":
w.setVisible(w.game.app_name in self.mac_games)
2021-09-02 05:41:01 +12:00
elif filter == "installable":
w.setVisible(w.game.app_name not in self.no_assets)
else:
# All visible
w.setVisible(True)
self.settings.setValue("filter", filter)
2021-02-18 05:46:03 +13:00
2021-05-18 06:22:29 +12:00
def update_list(self, app_name=None):
# self.settings.setValue("icon_view", icon_view)
if app_name:
if widgets := self.widgets.get(app_name):
2021-04-22 08:34:48 +12:00
2021-05-18 06:22:29 +12:00
# from update
if self.core.is_installed(widgets[0].game.app_name) and isinstance(widgets[0], BaseInstalledWidget):
igame = self.core.get_installed_game(app_name)
for w in widgets:
w.igame = igame
w.update_available = self.core.get_asset(w.game.app_name, True).build_version != igame.version
2021-05-18 20:32:46 +12:00
widgets[0].info_label.setText("")
2021-05-18 06:22:29 +12:00
widgets[0].info_text = ""
# new installed
elif self.core.is_installed(widgets[0].game.app_name) and not isinstance(widgets[0],
BaseInstalledWidget):
2021-05-18 06:22:29 +12:00
self.widgets.pop(widgets[0].game.app_name)
2021-04-22 08:34:48 +12:00
2021-05-18 06:22:29 +12:00
# QWidget().setLayout(self.icon_layout)
igame = self.core.get_installed_game(app_name)
self.add_installed_widget(igame)
self._update_games()
2021-05-18 06:22:29 +12:00
# uninstalled
elif not self.core.is_installed(widgets[0].game.app_name) and isinstance(widgets[0],
BaseInstalledWidget):
2021-05-18 06:22:29 +12:00
self.list_layout.removeWidget(widgets[1])
self.icon_layout.removeWidget(widgets[0])
self.widgets.pop(app_name)
game = self.core.get_game(app_name, True)
self.add_uninstalled_widget(game)
self._update_games()
2021-05-18 06:22:29 +12:00
else:
installed_names = [i.app_name for i in self.core.get_installed_list()]
# get Uninstalled games
2021-05-27 22:58:34 +12:00
uninstalled_names = []
2021-05-18 06:22:29 +12:00
games = self.core.get_game_list(True)
for game in sorted(games, key=lambda x: x.app_title):
if not game.app_name in installed_names:
2021-05-27 22:58:34 +12:00
uninstalled_names.append(game.app_name)
2021-05-18 06:22:29 +12:00
new_installed_games = list(set(installed_names) - set([i.app_name for i in self.installed]))
2021-05-27 22:58:34 +12:00
new_uninstalled_games = list(set(uninstalled_names) - set([i.app_name for i in self.uninstalled_games]))
2021-05-18 06:22:29 +12:00
if (not new_uninstalled_games) and (not new_installed_games):
return
2021-02-18 05:46:03 +13:00
2021-05-18 06:22:29 +12:00
if new_installed_games:
for name in new_installed_games:
self.icon_layout.removeWidget(self.widgets[app_name][0])
self.list_layout.removeWidget(self.widgets[app_name][1])
2021-04-22 08:34:48 +12:00
2021-05-18 06:22:29 +12:00
self.widgets.pop(name)
2021-04-22 08:34:48 +12:00
2021-05-18 06:22:29 +12:00
igame = self.core.get_installed_game(name)
self.add_installed_widget(igame)
for name in new_uninstalled_games:
self.icon_layout.removeWidget(self.widgets[app_name][0])
self.list_layout.removeWidget(self.widgets[app_name][1])
self.widgets.pop(name)
game = self.core.get_game(name, True)
self.add_uninstalled_widget(game)
for igame in sorted(self.core.get_installed_list(), key=lambda x: x.title):
i_widget, list_widget = self.widgets[igame.app_name]
self.icon_layout.addWidget(i_widget)
self.list_layout.addWidget(list_widget)
# get Uninstalled games
games, self.dlcs = self.core.get_game_and_dlc_list()
for game in sorted(games, key=lambda x: x.app_title):
if not game.app_name in installed_names:
self.uninstalled_names.append(game)
2021-05-27 22:58:34 +12:00
for name in uninstalled_names:
2021-05-18 06:22:29 +12:00
i_widget, list_widget = self.widgets[name]
self.icon_layout.addWidget(i_widget)
self.list_layout.addWidget(list_widget)
self.installing_widget.setVisible(False)
def _update_games(self):
# new layouts to remove from old layout
icon_layout = FlowLayout()
# QWidget().setLayout(self.list_layout)
list_layout = QVBoxLayout()
icon_layout.addWidget(self.installing_widget)
for igame in sorted(self.core.get_installed_list(), key=lambda x: x.title):
i_widget, l_widget = self.widgets[igame.app_name]
icon_layout.addWidget(i_widget)
list_layout.addWidget(l_widget)
self.uninstalled_names = []
installed_names = [i.app_name for i in self.core.get_installed_list()]
# get Uninstalled games
games, self.dlcs = self.core.get_game_and_dlc_list()
for game in sorted(games, key=lambda x: x.app_title):
if not game.app_name in installed_names:
self.uninstalled_names.append(game)
for game in self.uninstalled_names:
i_widget, list_widget = self.widgets[game.app_name]
icon_layout.addWidget(i_widget)
list_layout.addWidget(list_widget)
QWidget().setLayout(self.icon_layout)
QWidget().setLayout(self.list_layout)
self.icon_widget = QWidget()
self.list_widget = QWidget()
self.icon_widget.setLayout(icon_layout)
self.list_widget.setLayout(list_layout)
self.list_scrollarea.setWidget(QWidget())
self.icon_scrollarea.setWidget(QWidget())
self.icon_scrollarea.setWidget(self.icon_widget)
self.list_scrollarea.setWidget(self.list_widget)
self.icon_layout = icon_layout
self.list_layout = list_layout
self.icon_widget.setLayout(self.icon_layout)
self.list_widget.setLayout(self.list_layout)
self.update()