Skip to content

Commit

Permalink
Games List: Add checks for skipping invalid games (#401)
Browse files Browse the repository at this point in the history
* Games List: Add checks for skipping invalid games

Some games in the Lutris `pga.db` are missing data,
in most cases this is a result of a game that we
don't want to display on the games list.

Add a method to the Games List dialog that will check
for and skip games missing certain pieces of info,
such as the game runner and install_dir.

When querying the Lutris DB, it appears that only
not-installed Steam games were missing a runner.
As a result they were not being skipped by the
Steam runner skip check, and we were getting
a whole bunch of errors for trying to do operations
on NoneType.

Valid games for the Games List should have a runner
and an install_dir if they are actually installed.
So we skip if they don't meet this criteria, as well
as continuing to skip if a game is a Steam game.

We also add some more None-safe logic to
our installed_at parsing. This also probably
will never be missing but there is no harm in accounting
for it being missing.

* Games List: comment updates

* Games List: Update type hinting for Python3.10
  • Loading branch information
sonic2kk authored May 24, 2024
1 parent b9c0626 commit fcf0eaa
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 14 deletions.
11 changes: 9 additions & 2 deletions pupgui2/lutrisutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,17 @@ def get_lutris_game_list(install_loc) -> List[LutrisGame]:
lutris_install_dir = g[5]
if not lutris_install_dir:
lg_config = lg.get_game_config()
working_dir = lg_config.get('game', {}).get('working_dir')
exe_dir = lg_config.get('game', {}).get('exe')
lg_game_config = lg_config.get('game', {})

working_dir = lg_game_config.get('working_dir')
exe_dir = lg_game_config.get('exe')

lutris_install_dir = working_dir or (os.path.dirname(str(exe_dir)) if exe_dir else None)

# If a LutrisGame config has an 'appid' in its 'game' section in its yml, assume runner is Steam
if lg_game_config.get('appid', None) is not None:
lg.runner = 'steam'

lg.install_dir = os.path.abspath(lutris_install_dir) if lutris_install_dir else ''
lgs.append(lg)
except Exception as e:
Expand Down
62 changes: 50 additions & 12 deletions pupgui2/pupgui2gamelistdialog.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import os
import pkgutil

from typing import List, Callable, Tuple, Union
from typing import Callable
from datetime import datetime

from PySide6.QtCore import QObject, Signal, Slot, QDataStream, QByteArray, Qt
Expand Down Expand Up @@ -31,7 +31,7 @@ def __init__(self, install_dir, parent=None):
self.install_dir = install_dir
self.parent = parent
self.queued_changes = {}
self.games: List[Union[SteamApp, LutrisGame, HeroicGame]] = []
self.games: list[SteamApp | LutrisGame | HeroicGame] = []

self.install_loc = get_install_location_from_directory_name(install_dir)
self.launcher = self.install_loc.get('launcher', '')
Expand Down Expand Up @@ -111,7 +111,7 @@ def setup_heroic_list_ui(self):

def update_game_list_steam(self, cached=True):
""" update the game list for the Steam launcher """
self.games = get_steam_game_list(steam_config_folder=self.install_loc.get('vdf_dir'), cached=cached)
self.games: list[SteamApp] = get_steam_game_list(steam_config_folder=self.install_loc.get('vdf_dir'), cached=cached)
ctools = [c if c != 'SteamTinkerLaunch' else 'Proton-stl' for c in sort_compatibility_tool_names(list_installed_ctools(self.install_dir, without_version=True), reverse=True)]
ctools.extend(t.ctool_name for t in get_steam_ctool_list(steam_config_folder=self.install_loc.get('vdf_dir'), cached=True))

Expand Down Expand Up @@ -180,13 +180,13 @@ def update_game_list_lutris(self):
""" update the game list for the Lutris launcher """
# Filter blank runners and Steam games, because we can't change any compat tool options for Steam games via Lutris
# Steam games can be seen from the Steam games list, so no need to duplicate it here
self.games = [game for game in get_lutris_game_list(self.install_loc) if not is_lutris_game_using_runner(game, 'steam')]
self.games: list[LutrisGame] = [game for game in get_lutris_game_list(self.install_loc) if self.is_valid_lutris_gameslist_game(game)]

self.ui.tableGames.setRowCount(len(self.games))

# Not sure if we can allow compat tool updating from here, as Lutris allows configuring more than just Wine version
# It lets you set Wine/DXVK/vkd3d/etc independently, so for now the dialog just displays game information
for i, game in enumerate(self.games):
for i, game in enumerate(self.games):
name_item = QTableWidgetItem(game.name)
name_item.setToolTip(f'{game.name} ({game.slug})')
if game.installer_slug:
Expand All @@ -212,16 +212,25 @@ def update_game_list_lutris(self):
runner_item.setToolTip(tooltip)

# Some games may be in Lutris but not have a valid install path, though the yml should *usually* have some path
install_dir_text = game.install_dir or self.tr('Unknown')
install_dir_text = game.install_dir
install_dir_item = QTableWidgetItem(install_dir_text)
self.set_item_data_directory(install_dir_item, install_dir_text)

install_date = datetime.fromtimestamp(int(game.installed_at)).isoformat().split('T')
install_date_short = f'{install_date[0]}'
install_date_tooltip = self.tr('Installed at {DATE} ({TIME})').format(DATE=install_date[0], TIME=install_date[1])
# Populate Install Date column if we have game.install_date
# Otherwise set to some safe Unknown values
if game.installed_at:
install_date = datetime.fromtimestamp(int(game.installed_at)).isoformat().split('T')
install_date_short = f'{install_date[0]}'
install_date_tooltip = self.tr('Installed at {DATE} ({TIME})').format(DATE=install_date[0], TIME=install_date[1])
install_date_data = int(game.installed_at)
else:
install_date = self.tr('Unknown')
install_date_short = self.tr('Unknown')
install_date_tooltip = self.tr('Install Date is Unknown')
install_date_data = 0

install_date_item = QTableWidgetItem(install_date_short)
install_date_item.setData(Qt.UserRole, int(game.installed_at))
install_date_item.setData(Qt.UserRole, install_date_data)
install_date_item.setToolTip(install_date_tooltip)
install_date_item.setTextAlignment(Qt.AlignCenter)

Expand All @@ -232,7 +241,7 @@ def update_game_list_lutris(self):

def update_game_list_heroic(self):
heroic_dir = os.path.join(os.path.expanduser(self.install_loc.get('install_dir')), '../..')
self.games = list(filter(lambda heroic_game: (heroic_game.is_installed and len(heroic_game.runner) > 0 and not heroic_game.is_dlc), get_heroic_game_list(heroic_dir)))
self.games: list[HeroicGame] = list(filter(lambda heroic_game: (heroic_game.is_installed and len(heroic_game.runner) > 0 and not heroic_game.is_dlc), get_heroic_game_list(heroic_dir)))

self.ui.tableGames.setRowCount(len(self.games))

Expand Down Expand Up @@ -390,7 +399,7 @@ def set_item_data_directory(self, item: QTableWidgetItem, path: str,
else:
item.setToolTip(tooltip_invalid)

def get_steamapp_awacystatus(self, game: SteamApp) -> Tuple[str, str]:
def get_steamapp_awacystatus(self, game: SteamApp) -> tuple[str, str]:
""" Return translated status text and icon representing AreWeAntiCheatYet.com status for a Steam game """
awacy_status: str = ''
awacy_icon: str = ''
Expand Down Expand Up @@ -441,3 +450,32 @@ def get_steamdeck_compatibility(self, game: SteamApp) -> str:
return self.tr('Verified for {compat_tool}').format(compat_tool=deckt)
else:
return ''

def is_valid_lutris_gameslist_game(self, game: LutrisGame) -> bool:
"""
Check if a LutrisGame should be displayed on the Games List based on some criteria.
* Steam Games are excluded.
* Games with no runner are excluded.
* Games with no install_dir are excluded.
Return Type: bool
"""

# Lutris DB may store Steam games even if they are not installed
#
# This results in only the game.name being available, and many
# other values like game.runner and game.install_dir being 'None'
#
# We can assume a game is not valid to display on the Games List
# if the runner and install_dir are Falsey, and if

if not game.runner:
return False

if not game.install_dir:
return False

if is_lutris_game_using_runner(game, 'steam'):
return False

return True

0 comments on commit fcf0eaa

Please sign in to comment.