def main(): # Arguments parser = argparse.ArgumentParser( description='Borderlands 3 Profile Info Dumper v{}'.format( bl3save.__version__), ) parser.add_argument( '-V', '--version', action='version', version='BL3 CLI SaveEdit v{}'.format(bl3save.__version__), ) parser.add_argument( '-v', '--verbose', action='store_true', help='Show all available information', ) parser.add_argument( '-i', '--items', action='store_true', help='Show inventory items', ) parser.add_argument( 'filename', help='Filename to process', ) args = parser.parse_args() # Load the profile prof = BL3Profile(args.filename) # Golden Keys print('Keys:') print(' - Golden Keys: {}'.format(prof.get_golden_keys())) print(' - Diamond Keys: {}'.format(prof.get_diamond_keys())) print(' - Vault Card 1 Keys: {}'.format(prof.get_vaultcard1_keys())) print(' - Vault Card 1 Chests: {}'.format(prof.get_vaultcard1_chests())) print(' - Vault Card 2 Keys: {}'.format(prof.get_vaultcard2_keys())) print(' - Vault Card 2 Chests: {}'.format(prof.get_vaultcard2_chests())) print(' - Vault Card 3 Keys: {}'.format(prof.get_vaultcard3_keys())) print(' - Vault Card 3 Chests: {}'.format(prof.get_vaultcard3_chests())) # Guardian Rank print('Guardian Rank: {}'.format(prof.get_guardian_rank())) print('Available GR Tokens: {}'.format(prof.get_guardian_rank_tokens())) # Borderlands Science print("Borderlands Science Level: {}".format( prof.get_borderlands_science_level())) print("Available BS Tokens: {}".format( prof.get_borderlands_science_tokens())) # SDUs sdus = prof.get_sdus_with_max(True) if len(sdus) == 0: print('No SDUs Purchased') else: print('SDUs:') for sdu, (count, max_sdus) in sdus.items(): print(' - {}: {}/{}'.format(sdu, count, max_sdus)) # Bank Items bank_items = prof.get_bank_items() print('Items in bank: {}'.format(len(bank_items))) if args.verbose or args.items: to_report = [] for item in bank_items: if item.eng_name: to_report.append(' - {} ({}): {}'.format( item.eng_name, item.get_level_eng(), item.get_serial_base64())) else: to_report.append(' - unknown item: {}'.format( item.get_serial_base64())) for line in sorted(to_report): print(line) # Lost Loot Items lostloot_items = prof.get_lostloot_items() print('Items in Lost Loot machine: {}'.format(len(lostloot_items))) if args.verbose or args.items: to_report = [] for item in lostloot_items: if item.eng_name: to_report.append(' - {} ({}): {}'.format( item.eng_name, item.get_level_eng(), item.get_serial_base64())) else: to_report.append(' - unknown item: {}'.format( item.get_serial_base64())) for line in sorted(to_report): print(line) # Various customizations for (label, current, maxcount) in [ ('Character Skins', prof.get_char_skins(), prof.get_char_skins_total()), ('Character Heads', prof.get_char_heads(), prof.get_char_heads_total()), ('ECHO Themes', prof.get_echo_themes(), prof.get_echo_themes_total()), ('Emotes', prof.get_emotes(), prof.get_emotes_total()), ('Room Decorations', prof.get_room_decos(), prof.get_room_decos_total()), ('Weapon Skins', prof.get_weapon_skins(), prof.get_weapon_skins_total()), ('Weapon Trinkets', prof.get_weapon_trinkets(), prof.get_weapon_trinkets_total()), ]: print('{} Unlocked: {}/{}'.format(label, len(current), maxcount))
def main(): # Set up args parser = argparse.ArgumentParser( description='Borderlands 3 CLI Profile Editor v{} (PC Only)'.format( bl3save.__version__), formatter_class=argparse.ArgumentDefaultsHelpFormatter, epilog=""" The default output type of "profile" will output theoretically-valid profile which can be loaded into BL3. The output type "protobuf" will save out the extracted, decrypted protobufs. The output type "json" will output a JSON-encoded version of the protobufs in question. The output type "items" will output a text file containing base64-encoded representations of items in the user's bank. These can be read back in using the -i/--import-items option. Note that these are NOT the same as the item strings used by the BL3 Memory Editor. """) parser.add_argument( '-V', '--version', action='version', version='BL3 CLI SaveEdit v{}'.format(bl3save.__version__), ) parser.add_argument( '-o', '--output', choices=['profile', 'protobuf', 'json', 'items'], default='profile', help='Output file format', ) parser.add_argument( '--csv', action='store_true', help='When importing or exporting items, use CSV files', ) parser.add_argument( '-f', '--force', action='store_true', help='Force output file to overwrite', ) parser.add_argument('-q', '--quiet', action='store_true', help='Supress all non-essential output') # Now the actual arguments parser.add_argument( '--golden-keys', dest='golden_keys', type=int, help='Number of Golden Keys in the profile', ) parser.add_argument( '--diamond-keys', dest='diamond_keys', type=int, help='Number of Diamond Keys in the profile', ) parser.add_argument( '--vaultcard1-keys', dest='vaultcard1_keys', type=int, help='Number of Vault Card 1 Keys in the profile', ) parser.add_argument( '--vaultcard1-chests', dest='vaultcard1_chests', type=int, help='Number of Vault Card 1 Chests available in the profile', ) parser.add_argument( '--vaultcard2-keys', dest='vaultcard2_keys', type=int, help='Number of Vault Card 2 Keys in the profile', ) parser.add_argument( '--vaultcard2-chests', dest='vaultcard2_chests', type=int, help='Number of Vault Card 2 Chests available in the profile', ) parser.add_argument( '--vaultcard3-keys', dest='vaultcard3_keys', type=int, help='Number of Vault Card 3 Keys in the profile', ) parser.add_argument( '--vaultcard3-chests', dest='vaultcard3_chests', type=int, help='Number of Vault Card 3 Chests available in the profile', ) # Arguably we could be using a mutually-exclusive group for many of these # GR options, but I can see some potential value in specifying more than # one, so I'm not bothering. parser.add_argument( '--zero-guardian-rank', dest='zero_guardian_rank', action='store_true', help='Zero out profile Guardian Rank', ) parser.add_argument( '--min-guardian-rank', dest='min_guardian_rank', action='store_true', help= 'Set Guardian Rank to minimum required to prevent overwriting by saves', ) parser.add_argument( '--guardian-rank-rewards', dest='guardian_rank_rewards', type=int, help='Set Guardian Rank rewards to the specified number of tokens each', ) parser.add_argument( '--guardian-rank-tokens', dest='guardian_rank_tokens', type=int, help="Number of available Guardian Rank tokens", ) parser.add_argument( '--reset-borderlands-science', dest='reset_borderlands_science', action='store_true', help='Reset Borderlands Science progression', ) parser.add_argument( '--max-borderlands-science', dest='max_borderlands_science', action='store_true', help='Maximize Borderlands Science progression, unlocking True Tannis', ) parser.add_argument( '--remove-borderlands-science-boosts', dest='remove_borderlands_science_boosts', action='store_true', help='Remove the currently active borderlands science boost', ) parser.add_argument( '--borderlands-science-tokens', dest='borderlands_science_tokens', type=int, help="Number of available Borderlands Science tokens", ) itemlevelgroup = parser.add_mutually_exclusive_group() itemlevelgroup.add_argument('--item-levels-max', dest='item_levels_max', action='store_true', help='Set all bank items to max level') itemlevelgroup.add_argument( '--item-levels', dest='item_levels', type=int, help='Set all bank items to the specified level') itemmayhemgroup = parser.add_mutually_exclusive_group() itemmayhemgroup.add_argument( '--item-mayhem-max', dest='item_mayhem_max', action='store_true', help='Set all bank items to the maximum Mayhem level ({})'.format( bl3save.mayhem_max)) itemmayhemgroup.add_argument( '--item-mayhem-levels', dest='item_mayhem_levels', type=int, choices=range(bl3save.mayhem_max + 1), help='Set all bank items to the specified Mayhem level (0 to remove)') parser.add_argument( '-i', '--import-items', dest='import_items', type=str, help='Import items from file', ) parser.add_argument( '--allow-fabricator', dest='allow_fabricator', action='store_true', help='Allow importing Fabricator when importing items from file', ) parser.add_argument( '--clear-customizations', dest='clear_customizations', action='store_true', help='Remove all unlocked customizations', ) parser.add_argument( '--alpha', dest='alpha', action='store_true', help= 'Alphabetize unlocked room decorations, trinkets, and weapon skins', ) unlock_choices = [ 'lostloot', 'bank', 'skins', 'heads', 'echothemes', 'emotes', 'decos', 'weaponskins', 'trinkets', 'customizations', ] parser.add_argument( '--unlock', action=cli_common.DictAction, choices=unlock_choices + ['all'], default={}, help='Game features to unlock', ) # Positional args parser.add_argument( 'input_filename', help='Input filename', ) parser.add_argument( 'output_filename', help='Output filename', ) # Parse args args = parser.parse_args() # Expand any of our "all" unlock actions if 'all' in args.unlock: args.unlock = {k: True for k in unlock_choices} elif 'customizations' in args.unlock: args.unlock['skins'] = True args.unlock['heads'] = True args.unlock['echothemes'] = True args.unlock['emotes'] = True args.unlock['decos'] = True args.unlock['weaponskins'] = True args.unlock['trinkets'] = True # Set max item level arg if args.item_levels_max: args.item_levels = bl3save.max_level # Set max mayhem arg if args.item_mayhem_max: args.item_mayhem_levels = bl3save.mayhem_max # Check key counts; don't let them be below zero if args.golden_keys is not None and args.golden_keys < 0: raise argparse.ArgumentTypeError('Golden keys cannot be negative') if args.diamond_keys is not None and args.diamond_keys < 0: raise argparse.ArgumentTypeError('Diamond keys cannot be negative') if args.vaultcard1_keys is not None and args.vaultcard1_keys < 0: raise argparse.ArgumentTypeError( 'Vault Card 1 keys cannot be negative') if args.vaultcard1_chests is not None and args.vaultcard1_chests < 0: raise argparse.ArgumentTypeError( 'Vault Card 1 chests cannot be negative') if args.vaultcard2_keys is not None and args.vaultcard2_keys < 0: raise argparse.ArgumentTypeError( 'Vault Card 2 keys cannot be negative') if args.vaultcard2_chests is not None and args.vaultcard2_chests < 0: raise argparse.ArgumentTypeError( 'Vault Card 2 chests cannot be negative') if args.vaultcard3_keys is not None and args.vaultcard3_keys < 0: raise argparse.ArgumentTypeError( 'Vault Card 3 keys cannot be negative') if args.vaultcard3_chests is not None and args.vaultcard3_chests < 0: raise argparse.ArgumentTypeError( 'Vault Card 3 chests cannot be negative') # Check item level. The max storeable in the serial number is 127, but the # effective limit in-game is 100, thanks to MaxGameStage attributes. We # could use `bl3save.max_level` here, too, of course, but in the event that # I don't get this updated in a timely fashion, having it higher would let # this util potentially continue to be able to level up gear. if args.item_levels: if args.item_levels < 1 or args.item_levels > 100: raise argparse.ArgumentTypeError( 'Valid item level range is 1 through 100') if args.item_levels > bl3save.max_level: print( 'WARNING: Setting item levels to {}, when {} is the currently-known max' .format( args.item_levels, bl3save.max_level, )) # Check for overwrite warnings if os.path.exists(args.output_filename) and not args.force: if args.output_filename == args.input_filename: confirm_msg = 'Really overwrite {} with specified changes (no backup will be made)'.format( args.output_filename) else: confirm_msg = '{} already exists. Overwrite'.format( args.output_filename) sys.stdout.write('WARNING: {} [y/N]? '.format(confirm_msg)) sys.stdout.flush() response = sys.stdin.readline().strip().lower() if len(response) == 0 or response[0] != 'y': print('Aborting!') sys.exit(1) print('') # Now load the profile if not args.quiet: print('Loading {}'.format(args.input_filename)) profile = BL3Profile(args.input_filename) if not args.quiet: print('') # Check to see if we have any changes to make have_changes = any([ args.golden_keys is not None, args.diamond_keys is not None, args.vaultcard1_keys is not None, args.vaultcard1_chests is not None, args.vaultcard2_keys is not None, args.vaultcard2_chests is not None, args.vaultcard3_keys is not None, args.vaultcard3_chests is not None, args.zero_guardian_rank, args.min_guardian_rank, args.guardian_rank_rewards is not None, args.guardian_rank_tokens is not None, args.reset_borderlands_science, args.max_borderlands_science, args.remove_borderlands_science_boosts, args.borderlands_science_tokens is not None, len(args.unlock) > 0, args.import_items, args.item_levels, args.clear_customizations, args.alpha, args.item_mayhem_levels is not None, ]) # Alert about Guardian Rank stuff guardian_rank_alert = False # Make changes if have_changes: if not args.quiet: print('Making requested changes...') print('') # Golden Keys if args.golden_keys is not None: if not args.quiet: print(' - Setting Golden Key count to {}'.format( args.golden_keys)) profile.set_golden_keys(args.golden_keys) # Diamond Keys if args.diamond_keys is not None: if not args.quiet: print(' - Setting Diamond Key count to {}'.format( args.diamond_keys)) profile.set_diamond_keys(args.diamond_keys) # Vault Card 1 Keys if args.vaultcard1_keys is not None: if not args.quiet: print(' - Setting Vault Card 1 Key count to {}'.format( args.vaultcard1_keys)) profile.set_vaultcard1_keys(args.vaultcard1_keys) # Vault Card 1 Chests if args.vaultcard1_chests is not None: if not args.quiet: print(' - Setting Vault Card 1 Chest count to {}'.format( args.vaultcard1_chests)) profile.set_vaultcard1_chests(args.vaultcard1_chests) # Vault Card 2 Keys if args.vaultcard2_keys is not None: if not args.quiet: print(' - Setting Vault Card 2 Key count to {}'.format( args.vaultcard2_keys)) profile.set_vaultcard2_keys(args.vaultcard2_keys) # Vault Card 2 Chests if args.vaultcard2_chests is not None: if not args.quiet: print(' - Setting Vault Card 2 Chest count to {}'.format( args.vaultcard2_chests)) profile.set_vaultcard2_chests(args.vaultcard2_chests) # Vault Card 3 Keys if args.vaultcard3_keys is not None: if not args.quiet: print(' - Setting Vault Card 3 Key count to {}'.format( args.vaultcard3_keys)) profile.set_vaultcard3_keys(args.vaultcard3_keys) # Vault Card 3 Chests if args.vaultcard3_chests is not None: if not args.quiet: print(' - Setting Vault Card 3 Chest count to {}'.format( args.vaultcard3_chests)) profile.set_vaultcard3_chests(args.vaultcard3_chests) # Zeroing Guardian Rank if args.zero_guardian_rank: if not args.quiet: print(' - Zeroing Guardian Rank') if not args.min_guardian_rank \ and args.guardian_rank_rewards is None \ and args.guardian_rank_tokens is None: print( ' NOTE: A profile with a zeroed Guardian Rank will probably have its' ) print( ' Guardian Rank info populated from the first savegame loaded by the game' ) profile.zero_guardian_rank() # Setting Guardian rank to Minimum if args.min_guardian_rank: if not args.quiet: print( ' - Setting Guardian Rank to minimum (to prevent overwriting by savefiles)' ) new_gr = profile.min_guardian_rank() if new_gr is not None and not args.quiet: print(' - Guardian Rank set to {}'.format(new_gr)) guardian_rank_alert = True # Setting arbitrary Guardian Rank rewards if args.guardian_rank_rewards is not None: if not args.quiet: if args.guardian_rank_rewards == 1: plural = '' else: plural = 's' print(' - Setting Guardian Rank rewards to {} point{}'.format( args.guardian_rank_rewards, plural)) new_gr = profile.set_guardian_rank_reward_levels( args.guardian_rank_rewards, force=True) if new_gr is not None and not args.quiet: print(' - Also set Guardian Rank level to {}'.format(new_gr)) guardian_rank_alert = True # Setting Guardian Rank tokens if args.guardian_rank_tokens is not None: if not args.quiet: print(' - Setting available Guardian Rank tokens to {}'.format( args.guardian_rank_tokens)) new_gr = profile.set_guardian_rank_tokens( args.guardian_rank_tokens) if new_gr is not None and not args.quiet: print(' - Also set Guardian Rank level to {}'.format(new_gr)) guardian_rank_alert = True # Reset Borderlands Science progression if args.reset_borderlands_science: if not args.quiet: print(" - Resetting Borderlands Science progression") profile.reset_borderlands_science() if args.max_borderlands_science: if not args.quiet: print(" - Maximizing Borderlands Science progression") profile.max_borderlands_science() # Removing active Borderlands Science boosts if args.remove_borderlands_science_boosts: if not args.quiet: print(" - Removing active Borderlands Science boosts") profile.remove_borderlands_science_boosts() # Setting Borderlands Science tokens if args.borderlands_science_tokens is not None: if not args.quiet: print(" - Setting available Borderlands Science tokens to {}". format(args.borderlands_science_tokens)) profile.set_borderlands_science_tokens( args.borderlands_science_tokens) # Clear Customizations (do this *before* explicit customization unlocks) if args.clear_customizations: if not args.quiet: print(' - Clearing all customizations') profile.clear_all_customizations() # Unlocks if len(args.unlock) > 0: if not args.quiet: print(' - Processing Unlocks:') # Lost Loot if 'lostloot' in args.unlock: if not args.quiet: print(' - Lost Loot SDUs') profile.set_max_sdus([bl3save.PSDU_LOSTLOOT]) # Bank if 'bank' in args.unlock: if not args.quiet: print(' - Bank SDUs') profile.set_max_sdus([bl3save.PSDU_BANK]) # Skins if 'skins' in args.unlock: if not args.quiet: print(' - Character Skins') profile.unlock_char_skins() # Heads if 'heads' in args.unlock: if not args.quiet: print(' - Character Heads') profile.unlock_char_heads() # ECHO Themes if 'echothemes' in args.unlock: if not args.quiet: print(' - ECHO Themes') profile.unlock_echo_themes() # Emotes if 'emotes' in args.unlock: if not args.quiet: print(' - Emotes') profile.unlock_emotes() # Room Decorations if 'decos' in args.unlock: if not args.quiet: print(' - Room Decorations') profile.unlock_room_decos() # Weapon Skins if 'weaponskins' in args.unlock: if not args.quiet: print(' - Weapon Skins') profile.unlock_weapon_skins() # Weapon Trinkets if 'trinkets' in args.unlock: if not args.quiet: print(' - Weapon Trinkets') profile.unlock_weapon_trinkets() # Customization Alphabetization if args.alpha: if not args.quiet: print( ' - Alphabetizing Room Decorations, Trinkets, and Weapon Skins' ) profile.alphabetize_cosmetics() # Import Items if args.import_items: cli_common.import_items( args.import_items, profile.create_new_item_encoded, profile.add_bank_item, file_csv=args.csv, allow_fabricator=args.allow_fabricator, quiet=args.quiet, ) # Setting item levels. Keep in mind that we'll want to do this *after* # various of the actions above. If we've been asked to change the level # of items, we'll want to do it after the item import. if args.item_levels: cli_common.update_item_levels( profile.get_bank_items(), args.item_levels, quiet=args.quiet, ) # Item Mayhem level if args.item_mayhem_levels is not None: cli_common.update_item_mayhem_levels( profile.get_bank_items(), args.item_mayhem_levels, quiet=args.quiet, ) # Guardian Rank Alert if not args.quiet and guardian_rank_alert: print( ' - NOTE: Make sure to zero out your savegame Guardian Ranks, if making' ) print( ' changes to Guardian Rank in your profile, otherwise the changes might' ) print(' not take effect properly.') # Newline at the end of all this. if not args.quiet: print('') # Write out if args.output == 'profile': profile.save_to(args.output_filename) if not args.quiet: print('Wrote profile to {}'.format(args.output_filename)) elif args.output == 'protobuf': profile.save_protobuf_to(args.output_filename) if not args.quiet: print('Wrote protobuf to {}'.format(args.output_filename)) elif args.output == 'json': profile.save_json_to(args.output_filename) if not args.quiet: print('Wrote JSON to {}'.format(args.output_filename)) elif args.output == 'items': if args.csv: cli_common.export_items_csv( profile.get_bank_items(), args.output_filename, quiet=args.quiet, ) else: cli_common.export_items( profile.get_bank_items(), args.output_filename, quiet=args.quiet, ) else: # Not sure how we'd ever get here raise Exception('Invalid output format specified: {}'.format( args.output))
def main(): # Set up args parser = argparse.ArgumentParser( description='Import BL3 Profile JSON v{}'.format( bl3save.__version__), ) parser.add_argument( '-V', '--version', action='version', version='BL3 CLI SaveEdit v{}'.format(bl3save.__version__), ) parser.add_argument('-j', '--json', type=str, required=True, help='Filename containing JSON to import') parser.add_argument('-t', '--to-filename', dest='filename_to', type=str, required=True, help='Filename to import JSON into') parser.add_argument('-c', '--clobber', action='store_true', help='Clobber (overwrite) files without asking') # Parse args args = parser.parse_args() # Make sure that files exist if not os.path.exists(args.filename_to): raise Exception('Filename {} does not exist'.format(args.filename_to)) if not os.path.exists(args.json): raise Exception('Filename {} does not exist'.format(args.json)) # Load the profile file prof_file = BL3Profile(args.filename_to) # Load the JSON file and import (so we know it's valid before # we ask for confirmation) with open(args.json, 'rt') as df: prof_file.import_json(df.read()) # Ask for confirmation if not args.clobber: sys.stdout.write('Really import JSON from {} into {} [y/N]? '.format( args.json, args.filename_to, )) sys.stdout.flush() response = sys.stdin.readline().strip().lower() if response == 'y': pass else: print('') print('Aborting!') print('') sys.exit(1) # ... and save. prof_file.save_to(args.filename_to) # Report! print('') print('Done!') print('')
def main(): # Set up args parser = argparse.ArgumentParser( description='Borderlands 3 CLI Profile Editor v{} (PC Only)'.format( bl3save.__version__), formatter_class=argparse.ArgumentDefaultsHelpFormatter, epilog=""" The default output type of "profile" will output theoretically-valid profile which can be loaded into BL3. The output type "protobuf" will save out the extracted, decrypted protobufs. The output type "json" will output a JSON-encoded version of the protobufs in question. The output type "items" will output a text file containing base64-encoded representations of items in the user's bank. These can be read back in using the -i/--import-items option. Note that these are NOT the same as the item strings used by the BL3 Memory Editor. """) parser.add_argument( '-V', '--version', action='version', version='BL3 CLI SaveEdit v{}'.format(bl3save.__version__), ) parser.add_argument( '-o', '--output', choices=['profile', 'protobuf', 'json', 'items'], default='profile', help='Output file format', ) parser.add_argument( '-f', '--force', action='store_true', help='Force output file to overwrite', ) parser.add_argument('-q', '--quiet', action='store_true', help='Supress all non-essential output') # Now the actual arguments itemlevelgroup = parser.add_mutually_exclusive_group() itemlevelgroup.add_argument('--item-levels-max', dest='item_levels_max', action='store_true', help='Set all bank items to max level') itemlevelgroup.add_argument( '--item-levels', dest='item_levels', type=int, help='Set all bank items to the specified level') itemmayhemgroup = parser.add_mutually_exclusive_group() itemmayhemgroup.add_argument( '--item-mayhem-max', dest='item_mayhem_max', action='store_true', help='Set all bank items to the maximum Mayhem level ({})'.format( bl3save.mayhem_max)) itemmayhemgroup.add_argument( '--item-mayhem-levels', dest='item_mayhem_levels', type=int, choices=range(bl3save.mayhem_max + 1), help='Set all bank items to the specified Mayhem level (0 to remove)') parser.add_argument( '-i', '--import-items', dest='import_items', type=str, help='Import items from file', ) parser.add_argument( '--allow-fabricator', dest='allow_fabricator', action='store_true', help='Allow importing Fabricator when importing items from file', ) parser.add_argument( '--clear-customizations', dest='clear_customizations', action='store_true', help='Remove all unlocked customizations', ) parser.add_argument( '--alpha', dest='alpha', action='store_true', help= 'Alphabetize unlocked room decorations, trinkets, and weapon skins', ) unlock_choices = [ 'lostloot', 'bank', 'skins', 'heads', 'echothemes', 'emotes', 'decos', 'weaponskins', 'trinkets', 'customizations', ] parser.add_argument( '--unlock', action=cli_common.DictAction, choices=unlock_choices + ['all'], default={}, help='Game features to unlock', ) # Positional args parser.add_argument( 'input_filename', help='Input filename', ) parser.add_argument( 'output_filename', help='Output filename', ) # Parse args args = parser.parse_args() # Expand any of our "all" unlock actions if 'all' in args.unlock: args.unlock = {k: True for k in unlock_choices} elif 'customizations' in args.unlock: args.unlock['skins'] = True args.unlock['heads'] = True args.unlock['echothemes'] = True args.unlock['emotes'] = True args.unlock['decos'] = True args.unlock['weaponskins'] = True args.unlock['trinkets'] = True # Set max item level arg if args.item_levels_max: args.item_levels = bl3save.max_level # Set max mayhem arg if args.item_mayhem_max: args.item_mayhem_levels = bl3save.mayhem_max # Check item level. The max storeable in the serial number is 127, but the # effective limit in-game is 100, thanks to MaxGameStage attributes. We # could use `bl3save.max_level` here, too, of course, but in the event that # I don't get this updated in a timely fashion, having it higher would let # this util potentially continue to be able to level up gear. if args.item_levels: if args.item_levels < 1 or args.item_levels > 100: raise argparse.ArgumentTypeError( 'Valid item level range is 1 through 100') # Check for overwrite warnings if os.path.exists(args.output_filename) and not args.force: sys.stdout.write( 'WARNING: {} already exists. Overwrite [y/N]? '.format( args.output_filename)) sys.stdout.flush() response = sys.stdin.readline().strip().lower() if len(response) == 0 or response[0] != 'y': print('Aborting!') sys.exit(1) print('') # Now load the profile if not args.quiet: print('Loading {}'.format(args.input_filename)) profile = BL3Profile(args.input_filename) if not args.quiet: print('') # Check to see if we have any changes to make have_changes = any([ len(args.unlock) > 0, args.import_items, args.item_levels, args.clear_customizations, args.alpha, args.item_mayhem_levels is not None, ]) # Make changes if have_changes: if not args.quiet: print('Making requested changes...') print('') # Clear Customizations (do this *before* explicit customization unlocks) if args.clear_customizations: print(' - Clearing all customizations') profile.clear_all_customizations() # Unlocks if len(args.unlock) > 0: if not args.quiet: print(' - Processing Unlocks:') # Lost Loot if 'lostloot' in args.unlock: if not args.quiet: print(' - Lost Loot SDUs') profile.set_max_sdus([bl3save.PSDU_LOSTLOOT]) # Bank if 'bank' in args.unlock: if not args.quiet: print(' - Bank SDUs') profile.set_max_sdus([bl3save.PSDU_BANK]) # Skins if 'skins' in args.unlock: if not args.quiet: print(' - Character Skins') profile.unlock_char_skins() # Heads if 'heads' in args.unlock: if not args.quiet: print(' - Character Heads') profile.unlock_char_heads() # ECHO Themes if 'echothemes' in args.unlock: if not args.quiet: print(' - ECHO Themes') profile.unlock_echo_themes() # Emotes if 'emotes' in args.unlock: if not args.quiet: print(' - Emotes') profile.unlock_emotes() # Room Decorations if 'decos' in args.unlock: if not args.quiet: print(' - Room Decorations') profile.unlock_room_decos() # Weapon Skins if 'weaponskins' in args.unlock: if not args.quiet: print(' - Weapon Skins') profile.unlock_weapon_skins() # Weapon Trinkets if 'trinkets' in args.unlock: if not args.quiet: print(' - Weapon Trinkets') profile.unlock_weapon_trinkets() # Customization Alphabetization if args.alpha: if not args.quiet: print( ' - Alphabetizing Room Decorations, Trinkets, and Weapon Skins' ) profile.alphabetize_cosmetics() # Import Items if args.import_items: cli_common.import_items( args.import_items, profile.create_new_item_encoded, profile.add_bank_item, allow_fabricator=args.allow_fabricator, quiet=args.quiet, ) # Setting item levels. Keep in mind that we'll want to do this *after* # various of the actions above. If we've been asked to change the level # of items, we'll want to do it after the item import. if args.item_levels: cli_common.update_item_levels( profile.get_bank_items(), args.item_levels, quiet=args.quiet, ) # Item Mayhem level if args.item_mayhem_levels is not None: cli_common.update_item_mayhem_levels( profile.get_bank_items(), args.item_mayhem_levels, quiet=args.quiet, ) # Newline at the end of all this. if not args.quiet: print('') # Write out if args.output == 'profile': profile.save_to(args.output_filename) if not args.quiet: print('Wrote profile to {}'.format(args.output_filename)) elif args.output == 'protobuf': profile.save_protobuf_to(args.output_filename) if not args.quiet: print('Wrote protobuf to {}'.format(args.output_filename)) elif args.output == 'json': profile.save_json_to(args.output_filename) if not args.quiet: print('Wrote JSON to {}'.format(args.output_filename)) elif args.output == 'items': cli_common.export_items( profile.get_bank_items(), args.output_filename, quiet=args.quiet, ) else: # Not sure how we'd ever get here raise Exception('Invalid output format specified: {}'.format( args.output))