Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 9 additions & 14 deletions legendary/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -1392,6 +1392,7 @@ def import_game(self, args):
exe_path = case_insensitive_file_search(exe_path)
# check if most files at least exist or if user might have specified the wrong directory
total = len(manifest.file_manifest_list.elements)
# FIXME: This doesn't account for install tags
found = sum(os.path.exists(os.path.join(args.app_path, f.filename))
for f in manifest.file_manifest_list.elements)
ratio = found / total
Expand Down Expand Up @@ -1419,6 +1420,12 @@ def import_game(self, args):
logger.info(f'{"DLC" if game.is_dlc else "Game"} install appears to be complete.')

self.core.install_game(igame)

if args.install_tag and not game.is_dlc:
config_tags = ','.join(args.install_tag)
logger.info(f'Saving install tags for "{game.app_name}" to config: {config_tags}')
self.core.lgd.config.set(game.app_name, 'install_tags', config_tags)

if igame.needs_verification:
logger.info(f'NOTE: The {"DLC" if game.is_dlc else "Game"} installation will have to be '
f'verified before it can be updated with legendary.')
Expand Down Expand Up @@ -1454,12 +1461,6 @@ def egs_sync(self, args):
logger.info('Unlinking and resetting EGS and LGD sync...')
self.core.lgd.config.remove_option('Legendary', 'egl_programdata')
self.core.lgd.config.remove_option('Legendary', 'egl_sync')
# remove EGL GUIDs from all games, DO NOT remove .egstore folders because that would fuck things up.
for igame in self.core.get_installed_list():
if not igame.egl_guid:
continue
igame.egl_guid = ''
self.core.install_game(igame)
# todo track which games were imported, remove those from LGD and exported ones from EGL
logger.info('NOTE: All games are still available in Legendary and EGL, but future changes '
'will not be synced. This may cause issues when trying to update/uninstall games.')
Expand Down Expand Up @@ -1585,14 +1586,6 @@ def egs_sync(self, args):
logger.info('Disabling automatic sync (if enabled) and removing EGL link to finish migration...')
self.core.lgd.config.remove_option('Legendary', 'egl_programdata')
self.core.lgd.config.remove_option('Legendary', 'egl_sync')

for igame in self.core.get_installed_list():
if not igame.egl_guid:
continue
self.core.egl_uninstall(igame)
igame.egl_guid = ''
self.core.install_game(igame)

logger.info('Migration complete. Your games will now be exclusively managed by Legendary.')
else:
self.core.egl_sync()
Expand Down Expand Up @@ -3038,6 +3031,8 @@ def main():
help='Do not ask about importing DLCs.')
import_parser.add_argument('--platform', dest='platform', action='store', metavar='<Platform>', type=str,
help='Platform for import (default: Mac on macOS, otherwise Windows)')
import_parser.add_argument('--install-tag', dest='install_tag', action='store', metavar='<tag>', type=str,
help='Install tags used to install the game')

egl_sync_parser.add_argument('--egl-manifest-path', dest='egl_manifest_path', action='store',
help='Path to the Epic Games Launcher\'s Manifests folder, should '
Expand Down
38 changes: 23 additions & 15 deletions legendary/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -601,7 +601,7 @@ def get_installed_dlc_list(self) -> List[InstalledGame]:

def get_installed_game(self, app_name, skip_sync=False) -> InstalledGame:
igame = self._get_installed_game(app_name)
if not skip_sync and igame and self.egl_sync_enabled and igame.egl_guid and not igame.is_dlc:
if not skip_sync and igame and self.egl_sync_enabled and not igame.is_dlc:
self.egl_sync(app_name)
return self._get_installed_game(app_name)
else:
Expand Down Expand Up @@ -1684,14 +1684,19 @@ def get_default_install_dir(self, platform='Windows'):
return os.path.expanduser(self.lgd.config.get('Legendary', 'install_dir', fallback='~/Games'))

def install_game(self, installed_game: InstalledGame) -> dict:
if not installed_game.egl_guid:
installed_game.egl_guid = str(uuid4()).replace('-', '').upper()

if self.egl_sync_enabled and not installed_game.is_dlc and installed_game.platform.startswith('Win'):
if not installed_game.egl_guid:
installed_game.egl_guid = str(uuid4()).replace('-', '').upper()
prereq = self._install_game(installed_game)
self.egl_export(installed_game.app_name)
return prereq
else:
return self._install_game(installed_game)
prereq = self._install_game(installed_game)
game = self.lgd.get_game_meta(installed_game.app_name)
manifest_data, _ = self.get_installed_manifest(installed_game.app_name)
self._write_egstore(game, installed_game, manifest_data)
return prereq

def _install_game(self, installed_game: InstalledGame) -> dict:
"""Save game metadata and info to mark it "installed" and also show the user the prerequisites"""
Expand All @@ -1703,7 +1708,7 @@ def _install_game(self, installed_game: InstalledGame) -> dict:
return dict()

def uninstall_game(self, installed_game: InstalledGame, delete_files=True, delete_root_directory=False):
if installed_game.egl_guid:
if self.egl_sync_enabled:
self.egl_uninstall(installed_game, delete_files=delete_files)

if delete_files:
Expand Down Expand Up @@ -1762,6 +1767,7 @@ def import_game(self, game: Game, app_path: str, egl_guid='', platform='Windows'
if mancpn['AppName'] == game.app_name:
self.log.info('Found EGL install metadata, verifying...')
mf = f.replace('.mancpn', '.manifest')
egl_guid = f.replace('.mancpn', '')
break
else:
mf = f'{egl_guid}.manifest'
Expand Down Expand Up @@ -1900,24 +1906,29 @@ def egl_export(self, app_name):
# convert to egl manifest
egl_game = EGLManifest.from_lgd_game(lgd_game, lgd_igame)

self._write_egstore(lgd_game, lgd_igame, manifest_data)

# And finally, write the file for EGL
self.egl.set_manifest(egl_game)

@staticmethod
def _write_egstore(game: Game, igame: InstalledGame, manifest_data: bytes) -> None:
egl_game = EGLManifest.from_lgd_game(game, igame)
# make sure .egstore folder exists
egstore_folder = os.path.join(lgd_igame.install_path, '.egstore')
egstore_folder = os.path.join(igame.install_path, '.egstore')
if not os.path.exists(egstore_folder):
os.makedirs(egstore_folder)

# copy manifest and create mancpn file in .egstore folder
with open(os.path.join(egstore_folder, f'{egl_game.installation_guid}.manifest', ), 'wb') as mf:
mf.write(manifest_data)

mancpn = dict(FormatVersion=0, AppName=app_name,
CatalogItemId=lgd_game.catalog_item_id,
CatalogNamespace=lgd_game.namespace)
mancpn = dict(FormatVersion=0, AppName=game.app_name,
CatalogItemId=game.catalog_item_id,
CatalogNamespace=game.namespace)
with open(os.path.join(egstore_folder, f'{egl_game.installation_guid}.mancpn', ), 'w') as mcpnf:
json.dump(mancpn, mcpnf, indent=4, sort_keys=True)

# And finally, write the file for EGL
self.egl.set_manifest(egl_game)

def egl_uninstall(self, igame: InstalledGame, delete_files=True):
try:
self.egl.delete_manifest(igame.app_name)
Expand All @@ -1935,7 +1946,6 @@ def egl_restore_or_uninstall(self, igame):
if not os.path.exists(os.path.join(igame.install_path,
igame.executable.lstrip('/'))):
self.log.warning('Synced game\'s files no longer exists, assuming it has been uninstalled.')
igame.egl_guid = ''
return self.uninstall_game(igame, delete_files=False)
else:
self.log.info('Game files exist, assuming game is still installed, re-exporting to EGL...')
Expand Down Expand Up @@ -1983,8 +1993,6 @@ def egl_sync(self, app_name=''):

# Check for games that have been uninstalled
for lgd_igame in self._get_installed_list():
if not lgd_igame.egl_guid: # skip non-exported
continue
if lgd_igame.app_name in self.egl.manifests:
continue

Expand Down