mirror of
https://github.com/derrod/legendary.git
synced 2024-12-22 17:55:27 +00:00
[cli/core/models] Add support for importing already installed games
Fixes #10 though will need further improvement.
This commit is contained in:
parent
0d6bcf5950
commit
38f5bbd934
|
@ -389,6 +389,12 @@ class LegendaryCLI:
|
|||
subprocess.Popen(params, cwd=cwd, env=env)
|
||||
|
||||
def install_game(self, args):
|
||||
if self.core.is_installed(args.app_name):
|
||||
igame = self.core.get_installed_game(args.app_name)
|
||||
if igame.needs_verification and not args.repair_mode:
|
||||
logger.info('Game needs to be verified before updating, switching to repair mode...')
|
||||
args.repair_mode = True
|
||||
|
||||
repair_file = None
|
||||
if args.subparser_name == 'download':
|
||||
logger.info('Setting --no-install flag since "download" command was used')
|
||||
|
@ -472,6 +478,11 @@ class LegendaryCLI:
|
|||
if not analysis.dl_size:
|
||||
logger.info('Download size is 0, the game is either already up to date or has not changed. Exiting...')
|
||||
if args.repair_mode and os.path.exists(repair_file):
|
||||
igame = self.core.get_installed_game(game.app_name)
|
||||
if igame.needs_verification:
|
||||
igame.needs_verification = False
|
||||
self.core.install_game(igame)
|
||||
|
||||
logger.debug('Removing repair file.')
|
||||
os.remove(repair_file)
|
||||
exit(0)
|
||||
|
@ -557,6 +568,11 @@ class LegendaryCLI:
|
|||
logger.info(f'To download saves for this game run "legendary sync-saves {args.app_name}"')
|
||||
|
||||
if args.repair_mode and os.path.exists(repair_file):
|
||||
igame = self.core.get_installed_game(game.app_name)
|
||||
if igame.needs_verification:
|
||||
igame.needs_verification = False
|
||||
self.core.install_game(igame)
|
||||
|
||||
logger.debug('Removing repair file.')
|
||||
os.remove(repair_file)
|
||||
|
||||
|
@ -670,6 +686,46 @@ class LegendaryCLI:
|
|||
if print_command:
|
||||
logger.info(f'Run "legendary repair {args.app_name}" to repair your game installation.')
|
||||
|
||||
def import_game(self, args):
|
||||
if not os.path.exists(args.app_path):
|
||||
logger.error(f'Specified path "{args.app_path}" does not exist!')
|
||||
exit(1)
|
||||
|
||||
if self.core.is_installed(args.app_name):
|
||||
logger.error('Game is already installed!')
|
||||
exit(0)
|
||||
|
||||
if not self.core.login():
|
||||
logger.error('Log in failed!')
|
||||
exit(1)
|
||||
|
||||
# do some basic checks
|
||||
game = self.core.get_game(args.app_name, update_meta=True)
|
||||
if not game:
|
||||
logger.fatal(f'Did not find game "{args.app_name}" on account.')
|
||||
exit(1)
|
||||
|
||||
# todo: if there is an Epic Games Launcher manifest in the install path use that instead
|
||||
# get everything needed for import from core, then run additional checks.
|
||||
manifest, igame = self.core.import_game(game, args.app_path)
|
||||
# check if most files at least exist or if user might have specified the wrong directory
|
||||
total = len(manifest.file_manifest_list.elements)
|
||||
found = sum(os.path.exists(os.path.join(args.app_path, f.filename))
|
||||
for f in manifest.file_manifest_list.elements)
|
||||
if found != total:
|
||||
ratio = found / total
|
||||
if ratio < 0.95:
|
||||
logger.fatal(f'{total-found}/{total} files are missing, cannot import.')
|
||||
exit(1)
|
||||
logger.warning('Some files are missing from the game installation, this may be due to newer updates.')
|
||||
else:
|
||||
logger.info('Game install appears to be complete.')
|
||||
|
||||
self.core.install_game(igame)
|
||||
logger.info(f'NOTE: The game installation will have to be verified before it can be updated with legendary. '
|
||||
f'Run "legendary repair {args.app_name}" to do so.')
|
||||
logger.info('Game has been imported.')
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=f'Legendary v{__version__} - "{__codename__}"')
|
||||
|
@ -697,6 +753,7 @@ def main():
|
|||
download_saves_parser = subparsers.add_parser('download-saves', help='Download all cloud saves')
|
||||
sync_saves_parser = subparsers.add_parser('sync-saves', help='Sync cloud saves')
|
||||
verify_parser = subparsers.add_parser('verify-game', help='Verify a game\'s local files')
|
||||
import_parser = subparsers.add_parser('import-game', help='Import an already installed game')
|
||||
|
||||
install_parser.add_argument('app_name', help='Name of the app', metavar='<App Name>')
|
||||
uninstall_parser.add_argument('app_name', help='Name of the app', metavar='<App Name>')
|
||||
|
@ -709,7 +766,10 @@ def main():
|
|||
help='Name of the app (optional)')
|
||||
sync_saves_parser.add_argument('app_name', nargs='?', metavar='<App Name>', default='',
|
||||
help='Name of the app (optional)')
|
||||
verify_parser.add_argument('app_name', help='Name of the app (optional)', metavar='<App Name>')
|
||||
verify_parser.add_argument('app_name', help='Name of the app', metavar='<App Name>')
|
||||
import_parser.add_argument('app_name', help='Name of the app', metavar='<App Name>')
|
||||
import_parser.add_argument('app_path', help='Path where the game is installed',
|
||||
metavar='<Installation directory>')
|
||||
|
||||
# importing only works on Windows right now
|
||||
if os.name == 'nt':
|
||||
|
@ -835,7 +895,7 @@ def main():
|
|||
if args.subparser_name not in ('auth', 'list-games', 'list-installed', 'list-files',
|
||||
'launch', 'download', 'uninstall', 'install', 'update',
|
||||
'repair', 'list-saves', 'download-saves', 'sync-saves',
|
||||
'verify-game'):
|
||||
'verify-game', 'import-game'):
|
||||
print(parser.format_help())
|
||||
|
||||
# Print the main help *and* the help for all of the subcommands. Thanks stackoverflow!
|
||||
|
@ -883,6 +943,8 @@ def main():
|
|||
cli.sync_saves(args)
|
||||
elif args.subparser_name == 'verify-game':
|
||||
cli.verify_game(args)
|
||||
elif args.subparser_name == 'import-game':
|
||||
cli.import_game(args)
|
||||
except KeyboardInterrupt:
|
||||
logger.info('Command was aborted via KeyboardInterrupt, cleaning up...')
|
||||
|
||||
|
|
|
@ -754,6 +754,36 @@ class LegendaryCore:
|
|||
igame.prereq_info['installed'] = True
|
||||
self.lgd.set_installed_game(app_name, igame)
|
||||
|
||||
def import_game(self, game: Game, app_path: str) -> (Manifest, InstalledGame):
|
||||
self.log.info(f'Downloading latest manifest for "{game.app_name}"')
|
||||
manifest_data, base_urls = self.get_cdn_manifest(game)
|
||||
if not game.base_urls:
|
||||
game.base_urls = base_urls
|
||||
self.lgd.set_game_meta(game.app_name, game)
|
||||
|
||||
# parse and save manifest to disk for verification step of import
|
||||
new_manifest = self.load_manfiest(manifest_data)
|
||||
self.lgd.save_manifest(game.app_name, manifest_data)
|
||||
self.lgd.save_manifest(game.app_name, manifest_data,
|
||||
version=new_manifest.meta.build_version)
|
||||
|
||||
prereq = None
|
||||
if new_manifest.meta.prereq_ids:
|
||||
prereq = dict(ids=new_manifest.meta.prereq_ids, name=new_manifest.meta.prereq_name,
|
||||
path=new_manifest.meta.prereq_path, args=new_manifest.meta.prereq_args)
|
||||
|
||||
offline = game.metadata.get('customAttributes', {}).get('CanRunOffline', {}).get('value', 'true')
|
||||
ot = game.metadata.get('customAttributes', {}).get('OwnershipToken', {}).get('value', 'false')
|
||||
igame = InstalledGame(app_name=game.app_name, title=game.app_title, prereq_info=prereq, base_urls=base_urls,
|
||||
install_path=app_path, version=new_manifest.meta.build_version, is_dlc=game.is_dlc,
|
||||
executable=new_manifest.meta.launch_exe, can_run_offline=offline == 'true',
|
||||
launch_parameters=new_manifest.meta.launch_command, requires_ot=ot == 'true',
|
||||
needs_verification=True)
|
||||
|
||||
return new_manifest, igame
|
||||
|
||||
|
||||
|
||||
def exit(self):
|
||||
"""
|
||||
Do cleanup, config saving, and exit.
|
||||
|
|
|
@ -78,7 +78,8 @@ class Game:
|
|||
class InstalledGame:
|
||||
def __init__(self, app_name='', title='', version='', manifest_path='', base_urls=None,
|
||||
install_path='', executable='', launch_parameters='', prereq_info=None,
|
||||
can_run_offline=False, requires_ot=False, is_dlc=False, save_path=None):
|
||||
can_run_offline=False, requires_ot=False, is_dlc=False, save_path=None,
|
||||
needs_verification=False):
|
||||
self.app_name = app_name
|
||||
self.title = title
|
||||
self.version = version
|
||||
|
@ -93,6 +94,7 @@ class InstalledGame:
|
|||
self.requires_ot = requires_ot
|
||||
self.is_dlc = is_dlc
|
||||
self.save_path = save_path
|
||||
self.needs_verification = needs_verification
|
||||
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
|
@ -112,6 +114,7 @@ class InstalledGame:
|
|||
tmp.requires_ot = json.get('requires_ot', False)
|
||||
tmp.is_dlc = json.get('is_dlc', False)
|
||||
tmp.save_path = json.get('save_path', None)
|
||||
tmp.needs_verification = json.get('needs_verification', None)
|
||||
return tmp
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue