From 9685f7f7e733990615fea4020ebdeb3ddc873fdd Mon Sep 17 00:00:00 2001 From: loathingKernel <142770+loathingKernel@users.noreply.github.com> Date: Sat, 25 Apr 2026 21:04:03 +0300 Subject: [PATCH 1/3] chore: Ensure default directories exist on startup. Disable "Create shortcut" on Wine. --- rare/components/dialogs/install/dialog.py | 4 ++-- rare/models/settings.py | 7 ++++++- rare/shared/rare_core.py | 18 ++++++++++-------- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/rare/components/dialogs/install/dialog.py b/rare/components/dialogs/install/dialog.py index aa600af1b..9d68a5623 100644 --- a/rare/components/dialogs/install/dialog.py +++ b/rare/components/dialogs/install/dialog.py @@ -99,8 +99,8 @@ def __init__(self, settings: RareAppSettings, rgame: 'RareGame', options: Instal self.install_dir_edit.setDisabled(rgame.is_installed or rgame.is_dlc) self.ui.install_dir_label.setDisabled(rgame.is_installed or rgame.is_dlc) - 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_label.setDisabled(rgame.is_installed or rgame.is_dlc or 'WINEUSERNAME' in os.environ) + self.ui.shortcut_check.setDisabled(rgame.is_installed or rgame.is_dlc or 'WINEUSERNAME' in os.environ) 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) diff --git a/rare/models/settings.py b/rare/models/settings.py index bf0071fb5..a4b1a1e49 100644 --- a/rare/models/settings.py +++ b/rare/models/settings.py @@ -1,4 +1,5 @@ import locale +import os import platform as pf from argparse import Namespace from typing import Any, Optional @@ -59,7 +60,11 @@ class Settings(Namespace): discord_rpc_os = Setting(key='discord_rpc_os', default=True, dtype=bool) local_shader_cache = Setting(key='local_shader_cache', default=False, dtype=bool) - create_shortcut = Setting(key='create_shortcut', default=pf.system() == 'Windows', dtype=bool) + create_shortcut = Setting( + key='create_shortcut', + default=pf.system() == 'Windows' and 'WINEUSERNAME' not in os.environ, + dtype=bool + ) app_settings = Settings() diff --git a/rare/shared/rare_core.py b/rare/shared/rare_core.py index 0e7307ffa..62fce7145 100644 --- a/rare/shared/rare_core.py +++ b/rare/shared/rare_core.py @@ -46,7 +46,7 @@ class RareCore(QObject): # completed_entitlements = Signal() # lk: special case class attribute, this has to be here - __instance: Optional['RareCore'] = None + __instance: 'RareCore' = None def __init__(self, settings: RareAppSettings, args: Namespace): if self.__instance is not None: @@ -54,11 +54,11 @@ def __init__(self, settings: RareAppSettings, args: Namespace): super(RareCore, self).__init__() self.logger = getLogger(type(self).__name__) self.__settings = settings - self.__args: Namespace | None = None - self.__signals: GlobalSignals | None = None - self.__core: LegendaryCore | None = None - self.__image_manager: ImageManager | None = None - self.__wrappers: Wrappers | None = None + self.__args: Namespace = None + self.__signals: GlobalSignals = None + self.__core: LegendaryCore = None + self.__image_manager: ImageManager = None + self.__wrappers: Wrappers = None self.__start_time = time.perf_counter() @@ -196,12 +196,14 @@ def check_config(option: str, accepted: set = None) -> bool: self.__core.lgd.config.set('Legendary', 'default_platform', self.__core.default_platform) if not check_config('install_dir'): self.__core.lgd.config.set('Legendary', 'install_dir', self.__core.get_default_install_dir()) + os.makedirs(self.__core.get_default_install_dir(), exist_ok=True) if not check_config('mac_install_dir'): self.__core.lgd.config.set( 'Legendary', 'mac_install_dir', self.__core.get_default_install_dir(self.__core.default_platform), ) + os.makedirs(self.__core.get_default_install_dir(self.__core.default_platform), exist_ok=True) # Always set these options # Avoid implicitly falling back to Windows games on macOS @@ -320,7 +322,7 @@ def __filter_games(self, condition: Callable[[RareGame], bool]) -> Iterator[Rare return filter(condition, self.__library.values()) def __create_or_update_rgame(self, game: Game) -> RareGame: - if rgame := self.__library.get(game.app_name, False): + if rgame := self.__library.get(game.app_name): self.logger.warning(f'{rgame.app_name} already present in {type(self).__name__}') self.logger.info(f'Updating Game for {rgame.app_name}') rgame.update_rgame() @@ -333,7 +335,7 @@ def __add_games_and_dlcs(self, games: list[Game], dlcs_dict: dict[str, list]) -> length = len(games) for idx, game in enumerate(games): rgame = self.__create_or_update_rgame(game) - if game_dlcs := dlcs_dict.get(rgame.game.catalog_item_id, False): + if game_dlcs := dlcs_dict.get(rgame.game.catalog_item_id): for dlc in game_dlcs: rdlc = self.__create_or_update_rgame(dlc) if rdlc not in rgame.owned_dlcs: From c349177d385d0b6c8e2fd4dfbe64894a23b9d7ee Mon Sep 17 00:00:00 2001 From: loathingKernel <142770+loathingKernel@users.noreply.github.com> Date: Sat, 25 Apr 2026 21:14:16 +0300 Subject: [PATCH 2/3] WrapperExe: refactor --- rare/shared/rare_core.py | 8 +++--- rare/shared/workers/fetch.py | 8 +++--- rare/utils/paths.py | 2 +- rare/utils/wrapper_exe.py | 55 +++++++++++++++++++----------------- 4 files changed, 38 insertions(+), 35 deletions(-) diff --git a/rare/shared/rare_core.py b/rare/shared/rare_core.py index 62fce7145..e104ea0eb 100644 --- a/rare/shared/rare_core.py +++ b/rare/shared/rare_core.py @@ -84,7 +84,7 @@ def __init__(self, settings: RareAppSettings, args: Namespace): self.__fetch_progress: int = 0 self.__fetched_games_dlcs: bool = False self.__fetched_entitlements: bool = False - self.__fetched_steamappids: bool = False + self.__fetched_runtimeassets: bool = False RareCore.__instance = self @@ -368,8 +368,8 @@ def __on_fetch_result(self, result: tuple, result_type: int): self.__core.lgd.entitlements = result self.__fetched_entitlements = True - if result_type == FetchWorker.Result.EXTRAS: - self.__fetched_steamappids = True + if result_type == FetchWorker.Result.RUNTIMEASSETS: + self.__fetched_runtimeassets = True self.logger.info('Acquired data from %s worker', FetchWorker.Result(result_type).name) @@ -378,7 +378,7 @@ def __on_fetch_result(self, result: tuple, result_type: int): { self.__fetched_games_dlcs, self.__fetched_entitlements, - self.__fetched_steamappids, + self.__fetched_runtimeassets, } ): return diff --git a/rare/shared/workers/fetch.py b/rare/shared/workers/fetch.py index fadc67d96..5f6980f32 100644 --- a/rare/shared/workers/fetch.py +++ b/rare/shared/workers/fetch.py @@ -12,7 +12,7 @@ from rare.utils.metrics import timelogger from rare.utils.steam_grades import steam_grades from rare.utils.workarounds import workarounds -from rare.utils.wrapper_exe import download_wrapper_exe +from rare.utils.wrapper_exe import download_lgd_wrapper from .worker import Worker @@ -27,7 +27,7 @@ class Result(IntEnum): ERROR = 0 GAMESDLCS = 1 ENTITLEMENTS = 2 - EXTRAS = 3 + RUNTIMEASSETS = 3 def __init__(self, settings: RareAppSettings, core: LegendaryCore, args: Namespace, segment: int): super(FetchWorker, self).__init__() @@ -60,10 +60,10 @@ def run_real(self): self.signals.progress.emit(increment, self.signals.tr('Updating workarounds')) with timelogger(self.logger, 'Request wrapper exe'): try: - download_wrapper_exe() + download_lgd_wrapper() except Exception as e: self.logger.warning(e) - self.signals.result.emit((), FetchWorker.Result.EXTRAS) + self.signals.result.emit((), FetchWorker.Result.RUNTIMEASSETS) return diff --git a/rare/utils/paths.py b/rare/utils/paths.py index 6bb64dc0a..9dae704f6 100644 --- a/rare/utils/paths.py +++ b/rare/utils/paths.py @@ -85,7 +85,7 @@ def image_icon_path(app_name: str, color: bool = True) -> Path: return image_dir_game(app_name).joinpath('icon.png' if color else 'icon_gray.png') -def runtime_assets_json() -> Path: +def runtime_assets_path() -> Path: return data_dir().joinpath('runtime_assets.json') diff --git a/rare/utils/wrapper_exe.py b/rare/utils/wrapper_exe.py index 7bab3b24b..2070bb81a 100644 --- a/rare/utils/wrapper_exe.py +++ b/rare/utils/wrapper_exe.py @@ -1,10 +1,14 @@ from datetime import datetime +from logging import getLogger +from pathlib import Path import requests from orjson import orjson from rare.utils import config_helper as config -from rare.utils.paths import data_dir, runtime_assets_json +from rare.utils.paths import data_dir, runtime_assets_path + +logger = getLogger('WrapperExe') def version_tuple(version: str) -> tuple: @@ -14,61 +18,60 @@ def version_tuple(version: str) -> tuple: _github_api_url = 'https://api.github.com/repos/Etaash-mathamsetty/heroic-epic-integration/releases/latest' -def download_wrapper_exe(): - wrapper_exe = data_dir().joinpath('EpicGamesLauncher.exe') +def wrapper_path() -> Path: + return data_dir().joinpath('EpicGamesLauncher.exe') + - if not wrapper_exe.exists(): - config.remove_envvar('default', 'LEGENDARY_WRAPPER_EXE') +def download_lgd_wrapper() -> bool: + config.remove_envvar('default', 'LEGENDARY_WRAPPER_EXE') runtime_assets = { - wrapper_exe.name: { + wrapper_path().name: { 'version': 'v0.0', 'date': datetime.isoformat(datetime.min), } } - version = runtime_assets[wrapper_exe.name]['version'] + version = runtime_assets[wrapper_path().name]['version'] - if runtime_assets_json().exists(): - runtime_assets = orjson.loads(runtime_assets_json().open('r').read()) - version = runtime_assets.get(wrapper_exe.name, {}).get('version', 'v0.0') + if runtime_assets_path().exists(): + runtime_assets = orjson.loads(runtime_assets_path().open('r').read()) + version = runtime_assets.get(wrapper_path().name, {}).get('version', 'v0.0') try: resp = requests.get(_github_api_url, timeout=5) data = resp.content.decode('utf-8') latest_release = orjson.loads(data) except requests.exceptions.Timeout: - return + return wrapper_path().exists() remote_assets = latest_release['assets'] remote_version = latest_release['tag_name'] - if version_tuple(version) >= version_tuple(remote_version): - if wrapper_exe.exists() and config.get_envvar('default', 'LEGENDARY_WRAPPER_EXE', '') == str(wrapper_exe): - return - - if wrapper_exe.exists(): - config.set_envvar('default', 'LEGENDARY_WRAPPER_EXE', str(wrapper_exe)) - return + if version_tuple(version) >= version_tuple(remote_version) and wrapper_path().exists(): + logger.info('Legendary wrapper already up to date (%s)', version) + logger.debug('Path: %s', str(wrapper_path())) + return True download_url = remote_assets[0]['browser_download_url'] + logger.info('Updating Legendary wrapper (%s)', remote_version) try: resp = requests.get(download_url, timeout=5) - wrapper_exe.write_bytes(resp.content) - config.set_envvar('default', 'LEGENDARY_WRAPPER_EXE', str(wrapper_exe)) + wrapper_path().write_bytes(resp.content) + config.set_envvar('default', 'LEGENDARY_WRAPPER_EXE', str(wrapper_path)) except requests.exceptions.Timeout: - return + return False - runtime_assets[wrapper_exe.name] = { + runtime_assets[wrapper_path().name] = { 'version': remote_version, 'date': datetime.isoformat(datetime.fromisoformat(remote_assets[0]['created_at'].replace('Z', '+00:00'))), } - runtime_assets_json().write_text(orjson.dumps(runtime_assets).decode('utf-8'), encoding='utf-8') - return + runtime_assets_path().write_text(orjson.dumps(runtime_assets).decode('utf-8'), encoding='utf-8') + return True if __name__ == '__main__': - download_wrapper_exe() + download_lgd_wrapper() -__all__ = ['download_wrapper_exe'] +__all__ = ['download_lgd_wrapper', 'wrapper_path'] From dc718550a4edf85cf8916124de1bda8f32271608 Mon Sep 17 00:00:00 2001 From: loathingKernel <142770+loathingKernel@users.noreply.github.com> Date: Sun, 26 Apr 2026 01:30:51 +0300 Subject: [PATCH 3/3] LaunchSettings: add an option to use fake EGL exe --- rare/commands/launcher/lgd_helper.py | 13 +++--- rare/components/tabs/library/details/game.py | 29 ++++++++----- rare/components/tabs/settings/game.py | 6 ++- .../tabs/settings/widgets/launch.py | 42 ++++++++++++++----- rare/models/settings.py | 4 +- rare/shared/rare_core.py | 1 - rare/utils/config_helper.py | 37 ++++++++++------ rare/utils/workarounds.py | 6 +++ rare/utils/wrapper_exe.py | 2 - 9 files changed, 94 insertions(+), 46 deletions(-) diff --git a/rare/commands/launcher/lgd_helper.py b/rare/commands/launcher/lgd_helper.py index 721fb4703..4b5bc39f3 100644 --- a/rare/commands/launcher/lgd_helper.py +++ b/rare/commands/launcher/lgd_helper.py @@ -109,19 +109,18 @@ def get_game_params(rgame: RareGameSlim, init: InitParams, launch: LaunchParams) full_params = [] full_params.extend(params.launch_command) if 'LEGENDARY_WRAPPER_EXE' in params.environment: - lgd_wrapper = params.environment.pop('LEGENDARY_WRAPPER_EXE').strip() - if os.path.isfile(lgd_wrapper): + lgd_wrapper = params.environment.pop('LEGENDARY_WRAPPER_EXE', '').strip() + if lgd_wrapper and os.path.isfile(lgd_wrapper): full_params.append(lgd_wrapper) full_params.append(os.path.join(params.game_directory, params.game_executable)) full_params.extend(params.game_parameters) full_params.extend(params.egl_parameters) full_params.extend(params.user_parameters) - exe, init, env = prepare_process(full_params, params.environment) - - launch.executable = exe - launch.arguments = init - launch.environment = env + _exe, _init, _env = prepare_process(full_params, params.environment) + launch.executable = _exe + launch.arguments = _init + launch.environment = _env launch.working_directory = params.working_directory return launch diff --git a/rare/components/tabs/library/details/game.py b/rare/components/tabs/library/details/game.py index f4f8a57ca..ad5963362 100644 --- a/rare/components/tabs/library/details/game.py +++ b/rare/components/tabs/library/details/game.py @@ -13,6 +13,7 @@ from rare.models.settings import RareAppSettings from rare.shared import RareCore from rare.utils import config_helper as config +from rare.utils.wrapper_exe import wrapper_path from rare.widgets.indicator_edit import IndicatorReasonsCommon, PathEdit logger = getLogger('LocalGameSettings') @@ -34,13 +35,13 @@ def __init__(self, rcore: RareCore, parent=None): self.skip_update_combo.addItem(self.tr('Default'), None) self.skip_update_combo.addItem(self.tr('No'), 'false') self.skip_update_combo.addItem(self.tr('Yes'), 'true') - self.skip_update_combo.currentIndexChanged.connect(self.__skip_update_changed) + self.skip_update_combo.currentIndexChanged.connect(self._skip_update_changed) self.offline_combo = QComboBox(self) self.offline_combo.addItem(self.tr('Default'), None) self.offline_combo.addItem(self.tr('No'), 'false') self.offline_combo.addItem(self.tr('Yes'), 'true') - self.offline_combo.currentIndexChanged.connect(self.__offline_changed) + self.offline_combo.currentIndexChanged.connect(self._offline_changed) self.override_exe_name_filters: tuple[str, ...] = ( '*.exe', @@ -54,14 +55,14 @@ def __init__(self, rcore: RareCore, parent=None): file_mode=QFileDialog.FileMode.ExistingFile, name_filters=self.override_exe_name_filters, placeholder=self.tr('Relative path to the replacement executable'), - edit_func=self.__override_exe_edit_callback, - save_func=self.__override_exe_save_callback, + edit_func=self._override_exe_edit_callback, + save_func=self._override_exe_save_callback, parent=self, ) self.launch_params_edit = QLineEdit(self) self.launch_params_edit.setPlaceholderText(self.tr('Game specific command line arguments')) - self.launch_params_edit.textChanged.connect(self.__launch_params_changed) + self.launch_params_edit.textChanged.connect(self._launch_params_changed) self.main_layout.insertRow(0, self.tr('Skip update check'), self.skip_update_combo) self.main_layout.insertRow(1, self.tr('Offline mode'), self.offline_combo) @@ -94,11 +95,11 @@ def showEvent(self, a0: QShowEvent): return super().showEvent(a0) @Slot(int) - def __skip_update_changed(self, index): + def _skip_update_changed(self, index): data = self.skip_update_combo.itemData(index, Qt.ItemDataRole.UserRole) config.adjust_option(self.app_name, 'skip_update_check', data) - def __override_exe_edit_callback(self, path: str) -> tuple[bool, str, int]: + def _override_exe_edit_callback(self, path: str) -> tuple[bool, str, int]: if not path or self.igame is None: return True, path, IndicatorReasonsCommon.VALID if not os.path.isabs(path): @@ -116,17 +117,25 @@ def __override_exe_edit_callback(self, path: str) -> tuple[bool, str, int]: path = os.path.relpath(path, self.igame.install_path) return True, path, IndicatorReasonsCommon.VALID - def __override_exe_save_callback(self, path: str): + def _override_exe_save_callback(self, path: str): config.adjust_option(self.app_name, 'override_exe', path) @Slot(int) - def __offline_changed(self, index): + def _offline_changed(self, index): data = self.skip_update_combo.itemData(index, Qt.ItemDataRole.UserRole) config.adjust_option(self.app_name, 'offline', data) - def __launch_params_changed(self, value) -> None: + def _launch_params_changed(self, value) -> None: config.adjust_option(self.app_name, 'start_params', value) + @Slot(Qt.CheckState) + def _lgd_wrapper_check_changed(self, state: Qt.CheckState): + _wrapper = str(wrapper_path()) + config.adjust_envvar_with_global( + self.app_name, 'LEGENDARY_WRAPPER_EXE', _wrapper if state == Qt.CheckState.Checked else '' + ) + self.environ_changed.emit('LEGENDARY_WRAPPER_EXE') + def load_settings(self, rgame: RareGame): self.game = rgame.game self.igame = rgame.igame diff --git a/rare/components/tabs/settings/game.py b/rare/components/tabs/settings/game.py index 93d55a59c..3e3f711b9 100644 --- a/rare/components/tabs/settings/game.py +++ b/rare/components/tabs/settings/game.py @@ -1,4 +1,4 @@ -from PySide6.QtCore import Qt +from PySide6.QtCore import Qt, Signal from PySide6.QtGui import QHideEvent from PySide6.QtWidgets import QVBoxLayout, QWidget @@ -12,6 +12,9 @@ class GameSettingsBase(QWidget, SideTabContents): + # str: option key + environ_changed: Signal = Signal(str) + def __init__( self, settings: RareAppSettings, @@ -26,6 +29,7 @@ def __init__( self.app_name: str = 'default' self.launch = launch_widget(rcore, self) + self.launch.environ_changed.connect(self.environ_changed) self.main_layout = QVBoxLayout(self) self.main_layout.addWidget(self.launch, stretch=0) diff --git a/rare/components/tabs/settings/widgets/launch.py b/rare/components/tabs/settings/widgets/launch.py index 6141dbd13..63454ed36 100644 --- a/rare/components/tabs/settings/widgets/launch.py +++ b/rare/components/tabs/settings/widgets/launch.py @@ -3,7 +3,7 @@ import shutil from typing import TypeVar -from PySide6.QtCore import Qt, Slot +from PySide6.QtCore import Qt, Signal, Slot from PySide6.QtGui import QShowEvent from PySide6.QtWidgets import ( QCheckBox, @@ -16,12 +16,16 @@ import rare.utils.config_helper as config from rare.shared import RareCore +from rare.utils.wrapper_exe import wrapper_path from rare.widgets.indicator_edit import IndicatorReasonsCommon, PathEdit from .wrappers import WrapperSettings class LaunchSettingsBase(QGroupBox): + # str: option key + environ_changed: Signal = Signal(str) + def __init__(self, rcore: RareCore, wrapper_widget: type[WrapperSettings], parent=None): super(LaunchSettingsBase, self).__init__(parent=parent) self.setTitle(self.tr('Launch')) @@ -33,21 +37,21 @@ def __init__(self, rcore: RareCore, wrapper_widget: type[WrapperSettings], paren path='', placeholder=self.tr('Path to a script or program to run before the game'), file_mode=QFileDialog.FileMode.ExistingFile, - edit_func=self.__prelaunch_cmd_edit_callback, - save_func=self.__prelaunch_cmd_save_callback, + edit_func=self._prelaunch_cmd_edit_callback, + save_func=self._prelaunch_cmd_save_callback, ) self.prelaunch_args = QLineEdit('') self.prelaunch_args.setPlaceholderText(self.tr('Arguments to the script or program to run before the game')) self.prelaunch_args.setToolTip(self.prelaunch_args.placeholderText()) - self.prelaunch_args.textChanged.connect(self.__prelaunch_changed) + self.prelaunch_args.textChanged.connect(self._prelaunch_changed) font = self.font() font.setItalic(True) self.prelaunch_check = QCheckBox(self.tr('Wait for the pre-launch command to finish before launching the game')) self.prelaunch_check.setFont(font) - self.prelaunch_check.checkStateChanged.connect(self.__prelauch_check_changed) + self.prelaunch_check.checkStateChanged.connect(self._prelauch_check_changed) prelaunch_layout = QVBoxLayout() prelaunch_layout.addWidget(self.prelaunch_cmd) @@ -61,6 +65,13 @@ def __init__(self, rcore: RareCore, wrapper_widget: type[WrapperSettings], paren self.wrappers_widget = wrapper_widget(rcore, self) + self.lgd_wrapper = QCheckBox( + self.tr('Use "EpicGamesLauncher.exe" shim for compatibility with third-party launchers (Rockstar etc.)') + ) + self.lgd_wrapper.setFont(font) + self.lgd_wrapper.checkStateChanged.connect(self._lgd_wrapper_check_changed) + + self.main_layout.addRow(self.tr('Use fake EGL'), self.lgd_wrapper) self.main_layout.addRow(self.tr('Wrappers'), self.wrappers_widget) self.main_layout.addRow(self.tr('Pre-launch'), prelaunch_layout) @@ -77,6 +88,11 @@ def showEvent(self, a0: QShowEvent): self.prelaunch_check.setChecked(wait) self.prelaunch_check.setEnabled(bool(command)) + wrapper = config.get_envvar_with_global(self.app_name, 'LEGENDARY_WRAPPER_EXE', fallback=False) + + self.lgd_wrapper.setEnabled(wrapper_path().exists()) + self.lgd_wrapper.setChecked(wrapper_path().exists() and bool(wrapper) and os.path.exists(wrapper)) + return super().showEvent(a0) @Slot() @@ -84,7 +100,7 @@ def tool_enabled(self): self.wrappers_widget.update_state() @staticmethod - def __prelaunch_cmd_edit_callback(text: str) -> tuple[bool, str, int]: + def _prelaunch_cmd_edit_callback(text: str) -> tuple[bool, str, int]: if not text.strip(): return True, text, IndicatorReasonsCommon.UNDEFINED if not os.path.isfile(text) and not shutil.which(text): @@ -92,16 +108,16 @@ def __prelaunch_cmd_edit_callback(text: str) -> tuple[bool, str, int]: else: return True, text, IndicatorReasonsCommon.VALID - def __prelaunch_cmd_save_callback(self, text): + def _prelaunch_cmd_save_callback(self, text): self.prelaunch_check.setEnabled(bool(text)) - self.__prelaunch_changed() + self._prelaunch_changed() @Slot(Qt.CheckState) - def __prelauch_check_changed(self, state: Qt.CheckState): + def _prelauch_check_changed(self, state: Qt.CheckState): config.set_boolean(self.app_name, 'pre_launch_wait', state != Qt.CheckState.Unchecked) @Slot() - def __prelaunch_changed(self): + def _prelaunch_changed(self): command = self.prelaunch_cmd.text().strip() if not command: config.adjust_option(self.app_name, 'pre_launch_command', command) @@ -111,5 +127,11 @@ def __prelaunch_changed(self): arguments = self.prelaunch_args.text().strip() config.adjust_option(self.app_name, 'pre_launch_command', ' '.join([command, arguments])) + @Slot(Qt.CheckState) + def _lgd_wrapper_check_changed(self, state: Qt.CheckState): + _wrapper = str(wrapper_path()) + config.adjust_envvar(self.app_name, 'LEGENDARY_WRAPPER_EXE', _wrapper if state == Qt.CheckState.Checked else '') + self.environ_changed.emit('LEGENDARY_WRAPPER_EXE') + LaunchSettingsType = TypeVar('LaunchSettingsType', bound=LaunchSettingsBase) diff --git a/rare/models/settings.py b/rare/models/settings.py index a4b1a1e49..a050573c0 100644 --- a/rare/models/settings.py +++ b/rare/models/settings.py @@ -61,9 +61,7 @@ class Settings(Namespace): local_shader_cache = Setting(key='local_shader_cache', default=False, dtype=bool) create_shortcut = Setting( - key='create_shortcut', - default=pf.system() == 'Windows' and 'WINEUSERNAME' not in os.environ, - dtype=bool + key='create_shortcut', default=pf.system() == 'Windows' and 'WINEUSERNAME' not in os.environ, dtype=bool ) diff --git a/rare/shared/rare_core.py b/rare/shared/rare_core.py index e104ea0eb..d42e02c75 100644 --- a/rare/shared/rare_core.py +++ b/rare/shared/rare_core.py @@ -5,7 +5,6 @@ from collections.abc import Callable, Iterable, Iterator from itertools import chain from logging import getLogger -from typing import Optional from legendary.lfs.eos import EOSOverlayApp from legendary.models.game import Game, SaveGameFile diff --git a/rare/utils/config_helper.py b/rare/utils/config_helper.py index 683b0e202..962d46fe4 100644 --- a/rare/utils/config_helper.py +++ b/rare/utils/config_helper.py @@ -35,10 +35,6 @@ def set_boolean(app_name: str, option: str, value: bool) -> None: set_option(app_name, option, str(value).lower()) -def set_envvar(app_name: str, envvar: str, value: str) -> None: - set_option(f'{app_name}.env', envvar, value) - - def remove_section(app_name: str) -> None: return # Disabled due to env variables implementation @@ -55,10 +51,6 @@ def remove_option(app_name: str, option: str) -> None: # save_config() -def remove_envvar(app_name: str, option: str) -> None: - remove_option(f'{app_name}.env', option) - - def adjust_option(app_name: str, option: str, value: str) -> None: if value: set_option(app_name, option, value) @@ -70,6 +62,14 @@ def get_option(app_name: str, option: str, fallback: Any = None) -> str: return _config.get(app_name, option, fallback=fallback) +def adjust_option_with_global(app_name: str, option: str, value: str) -> None: + value = value if value else '' + if value == get_option('default', option, ''): + remove_option(app_name, option) + else: + set_option(app_name, option, value) + + def get_option_with_global(app_name: str, option: str, fallback: Any = None) -> str: _option = get_option('default', option, fallback=fallback) _option = get_option(app_name, option, fallback=_option) @@ -80,17 +80,30 @@ def get_boolean(app_name: str, option: str, fallback: bool = False) -> bool: return _config.getboolean(app_name, option, fallback=fallback) +def set_envvar(app_name: str, envvar: str, value: str) -> None: + set_option(f'{app_name}.env', envvar, value) + + +def remove_envvar(app_name: str, option: str) -> None: + remove_option(f'{app_name}.env', option) + + def adjust_envvar(app_name: str, option: str, value: str) -> None: - if value: - set_envvar(app_name, option, value) - else: - remove_envvar(app_name, option) + adjust_option(f'{app_name}.env', option, value) def get_envvar(app_name: str, option: str, fallback: Any = None) -> str: return get_option(f'{app_name}.env', option, fallback=fallback) +def adjust_envvar_with_global(app_name: str, option: str, value: str) -> None: + value = value if value else '' + if value == get_envvar('default', option, ''): + remove_envvar(app_name, option) + else: + set_envvar(app_name, option, value) + + def get_envvar_with_global(app_name: str, option: str, fallback: Any = None) -> str: _option = _config.get('default.env', option, fallback=fallback) _option = _config.get(f'{app_name}.env', option, fallback=_option) diff --git a/rare/utils/workarounds.py b/rare/utils/workarounds.py index ee3dec7f7..119758fda 100644 --- a/rare/utils/workarounds.py +++ b/rare/utils/workarounds.py @@ -7,6 +7,7 @@ from rare.utils import config_helper as config from rare.utils.paths import data_dir +from rare.utils.wrapper_exe import wrapper_path class Workarounds: @@ -70,11 +71,16 @@ def screen_height() -> int: def screen_width() -> int: return QApplication.instance().primaryScreen().geometry().width() + @staticmethod + def wrapper_exe() -> str: + return str(wrapper_path()) + @staticmethod def subst(text: str) -> str: return text.format( res_width=Workarounds.screen_width(), res_height=Workarounds.screen_height(), + wrapper_exe=Workarounds.wrapper_exe(), ) diff --git a/rare/utils/wrapper_exe.py b/rare/utils/wrapper_exe.py index 2070bb81a..52ab383cc 100644 --- a/rare/utils/wrapper_exe.py +++ b/rare/utils/wrapper_exe.py @@ -23,8 +23,6 @@ def wrapper_path() -> Path: def download_lgd_wrapper() -> bool: - config.remove_envvar('default', 'LEGENDARY_WRAPPER_EXE') - runtime_assets = { wrapper_path().name: { 'version': 'v0.0',