1
0
Fork 0
mirror of synced 2024-07-01 12:40:28 +12:00
Rare/rare/components/tabs/games/game_list.py

396 lines
17 KiB
Python

import os
from logging import getLogger
import psutil
from PyQt5.QtCore import Qt, pyqtSignal, QSettings, QTimer
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import QScrollArea, QWidget, QLabel, QVBoxLayout, QStackedWidget
from custom_legendary.core import LegendaryCore
from rare import data_dir
from rare.components.tabs.games.game_widgets.base_installed_widget import BaseInstalledWidget
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.uninstalled_icon_widget import IconWidgetUninstalled
from rare.components.tabs.games.game_widgets.uninstalled_list_widget import ListWidgetUninstalled
from rare.utils.extra_widgets import FlowLayout
from rare.utils.models import InstallOptionsModel
from rare.utils.utils import download_image
logger = getLogger("Game list")
class GameList(QStackedWidget):
install_game = pyqtSignal(InstallOptionsModel)
show_game_info = pyqtSignal(str)
update_game = pyqtSignal()
game_exited = pyqtSignal(str)
game_started = pyqtSignal(str)
show_uninstalled_info = pyqtSignal(str)
running_games = []
active_game = ("", 0)
def __init__(self, core: LegendaryCore, parent, offline):
super(GameList, self).__init__(parent=parent)
self.core = core
self.setObjectName("list_widget")
self.offline = offline
self.settings = QSettings()
icon_view = self.settings.value("icon_view", True, bool)
self.procs = [(proc.name(), proc.pid) for proc in psutil.process_iter()]
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)
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))
self.icon_layout = FlowLayout()
self.list_layout = QVBoxLayout()
self.list_layout.addWidget(QLabel(self.info_text))
self.IMAGE_DIR = self.settings.value("img_dir", os.path.join(data_dir, "images"), str)
self.updates = []
self.widgets = {}
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]]
self.installed = sorted(self.core.get_installed_list(), key=lambda x: x.title)
# Installed Games
for igame in self.installed:
icon_widget, list_widget = self.add_installed_widget(igame)
self.icon_layout.addWidget(icon_widget)
self.list_layout.addWidget(list_widget)
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()
for game in sorted(games, key=lambda x: x.app_title):
if not game.app_name in installed:
self.uninstalled_games.append(game)
# add uninstalled games
for game in self.uninstalled_games:
icon_widget, list_widget = self.add_uninstalled_widget(game)
self.icon_layout.addWidget(icon_widget)
self.list_layout.addWidget(list_widget)
self.icon_parent_layout.addLayout(self.icon_layout)
self.icon_parent_layout.addStretch(1)
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)
if filter_games := self.settings.value("filter", "", str):
self.filter(filter_games)
def add_uninstalled_widget(self, game):
if os.path.exists(f"{self.IMAGE_DIR}/{game.app_name}/UninstalledArt.png"):
pixmap = QPixmap(f"{self.IMAGE_DIR}/{game.app_name}/UninstalledArt.png")
if pixmap.isNull():
logger.info(game.app_title + " has a corrupt image.")
download_image(game, force=True)
pixmap = QPixmap(f"{self.IMAGE_DIR}/{game.app_name}/UninstalledArt.png")
else:
logger.warning(f"No Image found: {game.app_title}")
download_image(game, force=True)
pixmap = QPixmap(f"{self.IMAGE_DIR}/{game.app_name}/UninstalledArt.png")
icon_widget = IconWidgetUninstalled(game, self.core, pixmap)
icon_widget.show_uninstalled_info.connect(self.show_install_info)
list_widget = ListWidgetUninstalled(self.core, game, pixmap)
list_widget.show_uninstalled_info.connect(self.show_install_info)
self.widgets[game.app_name] = (icon_widget, list_widget)
return icon_widget, list_widget
def add_installed_widget(self, igame):
if os.path.exists(f"{self.IMAGE_DIR}/{igame.app_name}/FinalArt.png"):
pixmap = QPixmap(f"{self.IMAGE_DIR}/{igame.app_name}/FinalArt.png")
elif os.path.exists(f"{self.IMAGE_DIR}/{igame.app_name}/DieselGameBoxTall.png"):
pixmap = QPixmap(f"{self.IMAGE_DIR}/{igame.app_name}/DieselGameBoxTall.png")
elif os.path.exists(f"{self.IMAGE_DIR}/{igame.app_name}/DieselGameBoxLogo.png"):
pixmap = QPixmap(f"{self.IMAGE_DIR}/{igame.app_name}/DieselGameBoxLogo.png")
else:
logger.warning(f"No Image found: {igame.title}")
pixmap = None
if pixmap.isNull():
logger.info(igame.title + " has a corrupt image.")
download_image(igame, force=True)
pixmap = QPixmap(f"{self.IMAGE_DIR}/{igame.app_name}/DieselGameBoxTall.png")
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
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"):
executable = executable[:-4] # remove .exe
for i, pid in self.procs:
if executable in i:
# Workaround for Satisfactory: Check Cmdline args
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):
self.show_uninstalled_info.emit(app_name)
def finished(self, app_name):
self.running_games.remove(app_name)
self.active_game = ("", 0)
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"))
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"))
self.game_exited.emit(app_name)
def launch(self, app_name):
self.running_games.append(app_name)
self.game_started.emit(app_name)
self.widgets[app_name][0].info_text = self.tr("Game running")
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"))
def search(self, text: str):
for t in self.widgets.values():
for w in t:
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)
elif filter == "32bit":
w.setVisible(w.game.app_name in self.bit32)
elif filter == "mac":
w.setVisible(w.game.app_name in self.mac_games)
else:
# All visible
w.setVisible(True)
self.settings.setValue("filter", filter)
def update_list(self, app_name=None):
# self.settings.setValue("icon_view", icon_view)
if app_name:
if widgets := self.widgets.get(app_name):
# 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
widgets[0].info_label.setText("")
widgets[0].info_text = ""
# new installed
elif self.core.is_installed(widgets[0].game.app_name) and not isinstance(widgets[0],
BaseInstalledWidget):
self.widgets.pop(widgets[0].game.app_name)
# QWidget().setLayout(self.icon_layout)
icon_layout = FlowLayout()
# QWidget().setLayout(self.list_layout)
list_layout = QVBoxLayout()
igame = self.core.get_installed_game(app_name)
self.add_installed_widget(igame)
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()
# uninstalled
elif not self.core.is_installed(widgets[0].game.app_name) and isinstance(widgets[0],
BaseInstalledWidget):
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.icon_layout.addWidget(self.widgets[app_name][0])
self.list_layout.addWidget(self.widgets[app_name][1])
else:
installed_names = [i.app_name for i in self.core.get_installed_list()]
# get Uninstalled games
uninstalled_names = []
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:
uninstalled_names.append(game.app_name)
new_installed_games = list(set(installed_names) - set([i.app_name for i in self.installed]))
new_uninstalled_games = list(set(uninstalled_names) - set([i.app_name for i in self.uninstalled_games]))
if (not new_uninstalled_games) and (not new_installed_games):
return
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])
self.widgets.pop(name)
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)
for name in uninstalled_names:
i_widget, list_widget = self.widgets[name]
self.icon_layout.addWidget(i_widget)
self.list_layout.addWidget(list_widget)