From 0298a533158840df13352b1e4382145d34c403e3 Mon Sep 17 00:00:00 2001 From: derrod Date: Fri, 31 Dec 2021 18:46:09 +0100 Subject: [PATCH] [cli/core/utils] Add (janky) EOS overlay install support on non-Windows --- legendary/cli.py | 82 ++++++++++++++++++++++++++++++++---------- legendary/core.py | 22 ++++++++---- legendary/utils/eos.py | 22 ++++++++---- 3 files changed, 95 insertions(+), 31 deletions(-) diff --git a/legendary/cli.py b/legendary/cli.py index 9a679d2..20659c0 100644 --- a/legendary/cli.py +++ b/legendary/cli.py @@ -1950,13 +1950,41 @@ class LegendaryCLI: logger.info(f'Exchange code: {token["code"]}') def manage_eos_overlay(self, args): + prefix = None if os.name != 'nt': - logger.fatal('This command is only supported on Windows.') - return + if args.app: + app_name = self._resolve_aliases(args.app) + # try getting bottle/prefix from config + if sys_platform == 'darwin': + args.bottle = self.core.lgd.config.get(app_name, 'crossover_bottle', fallback=None) + + args.prefix = self.core.lgd.config.get(f'{app_name}.env', 'WINEPREFIX', fallback=None) + args.prefix = self.core.lgd.config.get(app_name, 'wine_prefix', fallback=args.prefix) + else: + # try using defaults if they exist + if sys_platform == 'darwin': + args.bottle = self.core.lgd.config.get('default', 'crossover_bottle', fallback=None) + + args.prefix = self.core.lgd.config.get('default.env', 'WINEPREFIX', fallback=None) + args.prefix = self.core.lgd.config.get('default', 'wine_prefix', fallback=args.prefix) + + if sys_platform == 'darwin' and args.bottle: + if not mac_is_valid_bottle(args.bottle): + logger.error('Invalid bottle specified.') + return + prefix = mac_get_bottle_path(args.bottle) + elif args.prefix: + if not os.path.exists(args.prefix): + logger.error(f'Prefix "{args.prefix}" does not exist.') + return + prefix = args.prefix + else: + logger.error('Need either config default, --prefix, --bottle, or --app to install the overlay to.') + return if args.action == 'info': - reg_paths = query_registry_entries() - available_installs = self.core.search_overlay_installs() + reg_paths = query_registry_entries(prefix) + available_installs = self.core.search_overlay_installs(prefix) igame = self.core.lgd.get_overlay_install_info() if not igame: logger.info('No Legendary-managed installation found.') @@ -1991,7 +2019,7 @@ class LegendaryCLI: if igame: args.path = igame.install_path else: - available_installs = self.core.search_overlay_installs() + available_installs = self.core.search_overlay_installs(prefix) args.path = available_installs[0] if not self.core.is_overlay_install(args.path): @@ -2000,22 +2028,22 @@ class LegendaryCLI: args.path = os.path.normpath(args.path) # Check for existing entries - reg_paths = query_registry_entries() + reg_paths = query_registry_entries(prefix) if old_path := reg_paths["overlay_path"]: if os.path.normpath(old_path) == args.path: logger.info(f'Overlay already enabled, nothing to do.') return else: logger.info(f'Updating overlay registry entries from "{old_path}" to "{args.path}"') - remove_registry_entries() - add_registry_entries(args.path) + remove_registry_entries(prefix) + add_registry_entries(args.path, prefix) logger.info(f'Enabled overlay at: {args.path}') elif args.action == 'disable': logger.info('Disabling overlay (removing registry keys)..') - reg_paths = query_registry_entries() + reg_paths = query_registry_entries(prefix) old_path = reg_paths["overlay_path"] - remove_registry_entries() + remove_registry_entries(prefix) # if the install is not managed by legendary, specify the command including the path if self.core.is_overlay_installed(): logger.info(f'To re-enable the overlay, run: legendary eos-overlay enable') @@ -2033,7 +2061,12 @@ class LegendaryCLI: return logger.info('Removing registry entries...') - remove_registry_entries() + remove_registry_entries(prefix) + + if os.name != 'nt': + logger.info(f'Registry entries in prefixes other than "{prefix}" were not removed. ' + f'This shoouldn\'t cause any issues as the overlay will simply fail to load.') + logger.info('Deleting overlay installation...') self.core.remove_overlay_install() logger.info('Done.') @@ -2073,15 +2106,15 @@ class LegendaryCLI: # Check for existing registry entries, and remove them if necessary install_path = os.path.normpath(igame.install_path) - reg_paths = query_registry_entries() + reg_paths = query_registry_entries(prefix) if old_path := reg_paths["overlay_path"]: if os.path.normpath(old_path) != install_path: logger.info(f'Updating overlay registry entries from "{old_path}" to "{install_path}"') - remove_registry_entries() + remove_registry_entries(prefix) else: logger.info(f'Registry entries already exist. Done.') return - add_registry_entries(install_path) + add_registry_entries(install_path, prefix) logger.info('Done.') def crossover_setup(self, args): @@ -2609,10 +2642,23 @@ def main(): metavar='') eos_overlay_parser.add_argument('--path', dest='path', action='store', help='Path to the EOS overlay folder to be enabled/installed to.') - # eos_overlay_parser.add_argument('--prefix', dest='prefix', action='store', - # help='WINE prefix to install the overlay in') - # eos_overlay_parser.add_argument('--app', dest='app', action='store', - # help='Use this app\'s wine prefix (if configured in config)') + + if os.name != 'nt': + eos_overlay_parser.add_argument('--prefix', dest='prefix', action='store', + help='WINE prefix to install the overlay in') + eos_overlay_parser.add_argument('--app', dest='app', action='store', + help='Use this app\'s wine prefix (if configured in config)') + + if sys_platform == 'darwin': + eos_overlay_parser.add_argument('--bottle', dest='bottle', action='store', + help='WINE prefix to install the overlay in') + else: + eos_overlay_parser.add_argument('--bottle', dest='prefix', action='store', help=argparse.SUPPRESS) + else: + eos_overlay_parser.add_argument('--prefix', dest='prefix', action='store', help=argparse.SUPPRESS) + eos_overlay_parser.add_argument('--bottle', dest='prefix', action='store', help=argparse.SUPPRESS) + eos_overlay_parser.add_argument('--app', dest='app', action='store', help=argparse.SUPPRESS) + cx_parser.add_argument('--reset', dest='reset', action='store_true', help='Reset default/app-specific crossover configuration') diff --git a/legendary/core.py b/legendary/core.py index c696dcb..b36952f 100644 --- a/legendary/core.py +++ b/legendary/core.py @@ -1755,22 +1755,30 @@ class LegendaryCore: def is_overlay_install(path): return os.path.exists(os.path.join(path, 'EOSOVH-Win64-Shipping.dll')) - def search_overlay_installs(self): + def search_overlay_installs(self, prefix=None): locations = [] install_info = self.lgd.get_overlay_install_info() if install_info: locations.append(install_info.install_path) - # Launcher path - locations.append(os.path.expandvars(r'%programfiles(x86)%\Epic Games\Launcher\Portal\Extras\Overlay')) - # EOSH path - locations.append(os.path.expandvars(f'%programfiles(x86)%\\Epic Games\\Epic Online Services' - f'\\managedArtifacts\\{EOSOverlayApp.app_name}')) + if os.name == 'nt': + # Launcher path + locations.append(os.path.expandvars(r'%programfiles(x86)%\Epic Games\Launcher\Portal\Extras\Overlay')) + # EOSH path + locations.append(os.path.expandvars(f'%programfiles(x86)%\\Epic Games\\Epic Online Services' + f'\\managedArtifacts\\{EOSOverlayApp.app_name}')) + else: + # Launcher path + locations.append(os.path.join(prefix, 'drive_c', 'Program Files (x86)', + 'Epic Games/Launcher/Portal/Extras/Overlay')) + # EOSH path + locations.append(os.path.join(prefix, 'drive_c', 'Program Files (x86)', + f'Epic Games/Epic Online Services/managedArtifacts/{EOSOverlayApp.app_name}')) # normalise all paths locations = [os.path.normpath(x) for x in locations] - paths = query_registry_entries() + paths = query_registry_entries(prefix) if paths['overlay_path']: reg_path = os.path.normpath(paths['overlay_path']) if reg_path not in locations: diff --git a/legendary/utils/eos.py b/legendary/utils/eos.py index f2ff6eb..3976664 100644 --- a/legendary/utils/eos.py +++ b/legendary/utils/eos.py @@ -59,6 +59,11 @@ def query_registry_entries(prefix=None): else: overlay_path = None + if overlay_path.startswith('C:'): + overlay_path = os.path.join(prefix, 'drive_c', overlay_path[3:]) + elif overlay_path.startswith('Z:'): + overlay_path = overlay_path[2:] + return dict(overlay_path=overlay_path, vulkan_hkcu=list(), vulkan_hklm=list()) @@ -87,7 +92,11 @@ def add_registry_entries(overlay_path, prefix=None): reg_lines = open(use_reg_file, 'r', encoding='utf-8').readlines() - overlay_line = f'"{EOS_OVERLAY_VALUE}"="Z:{overlay_path}"\n' + overlay_path = overlay_path.replace('\\', '/') + if overlay_path.startswith('/'): + overlay_path = f'Z:{overlay_path}' + + overlay_line = f'"{EOS_OVERLAY_VALUE}"="{overlay_path}"\n' overlay_idx = None section_idx = None @@ -110,9 +119,9 @@ def add_registry_entries(overlay_path, prefix=None): def remove_registry_entries(prefix=None): - if os.name == 'nt': - entries = query_registry_entries() + entries = query_registry_entries(prefix) + if os.name == 'nt': if entries['overlay_path']: logger.debug('Removing HKCU EOS OverlayPath') remove_registry_value(HKEY_CURRENT_USER, EOS_OVERLAY_KEY, EOS_OVERLAY_VALUE) @@ -129,8 +138,9 @@ def remove_registry_entries(prefix=None): if not os.path.exists(use_reg_file): raise ValueError('No user.reg file, invalid path') - reg_lines = open(use_reg_file, 'r', encoding='utf-8').readlines() - filtered_lines = [line for line in reg_lines if EOS_OVERLAY_VALUE not in line] - open(use_reg_file, 'w', encoding='utf-8').writelines(filtered_lines) + if entries['overlay_path']: + reg_lines = open(use_reg_file, 'r', encoding='utf-8').readlines() + filtered_lines = [line for line in reg_lines if EOS_OVERLAY_VALUE not in line] + open(use_reg_file, 'w', encoding='utf-8').writelines(filtered_lines) else: raise ValueError('No prefix specified on non-Windows platform')