def console_scan_regionset(regionset, processes, entity_limit, remove_entities, verbose): """ Scan a regionset printing status to console. Uses AsyncRegionsetScanner. """ rs = AsyncRegionsetScanner(regionset, processes, entity_limit, remove_entities) scanners = [rs] titles = [entitle("Scanning separate region files", 0)] console_scan_loop(scanners, titles, verbose) regionset.scanned = True
def console_scan_regionset(regionset, processes, entity_limit, remove_entities, verbose): """ Scan a regionset printing status to console. Inputs: - regionset -- RegionSet object from world.py that will be scanned - processes -- An integer with the number of child processes to use - entity_limit -- An integer, threshold of entities for a chunk to be considered with too many entities - remove_entities -- A boolean, defaults to False, to remove the entities whilel scanning. This is really handy because opening chunks with too many entities for scanning can take minutes. - verbose -- Boolean, if true it will print a line per scanned region file. """ rs = AsyncRegionsetScanner(regionset, processes, entity_limit, remove_entities) scanners = [rs] titles = [entitle("Scanning separate region files", 0)] console_scan_loop(scanners, titles, verbose) regionset.scanned = True
def main(): usage = ('usage: \n%prog [options] <world-path> ' '<other-world-path> ... <region-files> ...') epilog = ('Copyright (C) 2011 Alejandro Aguilera (Fenixin)\n' 'https://github.com/Fenixin/Minecraft-Region-Fixer\n' 'This program comes with ABSOLUTELY NO WARRANTY; for ' 'details see COPYING.txt. This is free software, and you ' 'are welcome to redistribute it under certain conditions; ' 'see COPYING.txt for details.') parser = OptionParser(description=('Program to check the integrity of ' 'Minecraft worlds and fix them when ' 'possible. It uses NBT by twoolie. ' 'Author: Alejandro Aguilera (Fenixin)'), prog='region_fixer', version=version_string, usage=usage, epilog=epilog) add_option = parser.add_option add_option('--backups', '-b', help=('List of backup directories of the Minecraft world ' 'to use to fix corrupted chunks and/or wrong located ' 'chunks. Warning! Region-Fixer is not going to check if' 'it\'s the same world, be careful! This argument can be a' ' comma separated list (but never with spaces between ' 'elements!). This option can be only used scanning one ' 'world.'), metavar='<backups>', type=str, dest='backups', default=None) add_option('--replace-corrupted', '--rc', help='Tries to replace the corrupted chunks using the backup' ' directories. This option can be only used scanning one' ' world.', default=False, dest='replace_corrupted', action='store_true') add_option('--replace-wrong-located', '--rw', help='Tries to replace the wrong located chunks using the ' 'backup directories. This option can be only used scanning' ' one world.', default=False, dest='replace_wrong_located', action='store_true') add_option('--replace-entities', '--re', help='Tries to replace the chunks with too many entities using ' 'the backup directories. This option can be only used ' 'scanning one world.', default=False, dest='replace_entities', action='store_true') add_option('--replace-shared-offset', '--rs', help='Tries to replace the chunks with a shared offset using ' 'the backup directories. This option can be only used' 'scanning one world.', default=False, dest='replace_shared_offset', action='store_true') add_option('--replace-too-small', '--rt', help='Tries to replace the region files that are too small to ' 'be actually be a region file using the backup ' 'directories. This option can be only used scanning one ' 'world.', default=False, dest='replace_too_small', action='store_true') add_option('--delete-corrupted', '--dc', help='[WARNING!] This option deletes! This option will delete ' 'all the corrupted chunks. Used with --replace-corrupted ' 'or --replace-wrong-located it will delete all the ' 'non-replaced chunks.', action='store_true', default=False) add_option('--delete-wrong-located', '--dw', help=('[WARNING!] This option deletes!' 'The same as --delete-corrupted but for wrong ' 'located chunks'), action='store_true', default=False, dest='delete_wrong_located') add_option('--delete-entities', '--de', help='[WARNING!] This option deletes! This option deletes ALL ' 'the entities in chunks with more entities than ' '--entity-limit (300 by default). In a Minecraft ' 'entities are mostly mobs and items dropped in the ' 'grond, items in chests and other stuff won\'t be ' 'touched. Read the README for more info. Region-Fixer ' 'will delete the entities while scanning so you can ' 'stop and resume the process', action='store_true', default=False, dest='delete_entities') add_option('--delete-shared-offset', '--ds', help='[WARNING!] This option deletes! This option will delete ' 'all the chunk with status shared offset. It will remove ' 'the region header for the false chunk, note that you ' 'don\'t loos any chunk doing this.', action='store_true', default=False, dest='delete_shared_offset') add_option('--delete-too-small', '--dt', help='[WARNING!] This option deletes! Removes any region files ' 'found to be too small to actually be a region file.', dest='delete_too_small', default=False, action='store_true') add_option('--entity-limit', '--el', help='Specify the limit for the --delete-entities option ' '(default = 300).', dest='entity_limit', default=300, action='store', type=int) add_option('--processes', '-p', help='Set the number of workers to use for scanning. (defaulta ' '= 1, not use multiprocessing at all)', action='store', type=int, default=1) add_option('--verbose', '-v', help='Don\'t use a progress bar, instead print a line per ' 'scanned region file with results information. The ' 'letters mean c: corrupted; w: wrong located; t: total of ' 'chunksm; tme: too many entities problem', action='store_true', default=False) add_option('--interactive', '-i', help='Enter in interactive mode, where you can scan, see the ' 'problems, and fix them in a terminal like mode', dest='interactive', default=False, action='store_true', ) add_option('--log', '-l', help='Saves a log of all the problems found in the spicifyed ' 'file. The log file contains all the problems found with ' 'this information: region file, chunk coordinates and ' 'problem. Use \'-\' as name to show the log at the end ' 'of the scan.', type=str, default=None, dest='summary') (options, args) = parser.parse_args() o = options if sys.version_info[0] > 2: print("") print("Minecraft Region Fixer only works with python 2.x") print("(And you just tried to run it in python {0})".format(sys.version)) print("") return 1 if is_bare_console(): print("") print("Minecraft Region Fixer hast a command line aplication and a GUI\n" "(Graphic User Interface) and you have just double clicked the\n" "command line interface. If you really want to run the command line\n" "interface you have to use a command prompt (cmd.exe)\n\n" "You can also run the gui, double click regionfixer_gui.py instead!") print("") getpass("Press enter to continue:") return 1 # Args are world_paths and region files if not args: parser.error('No world paths or region files specified! Use ' '--help for a complete list of options.') world_list, regionset = parse_paths(args) if not (world_list or regionset): print ("Error: No worlds or region files to scan!") return 1 # Check basic options compatibilities any_chunk_replace_option = o.replace_corrupted or o.replace_wrong_located or o.replace_entities or o.replace_shared_offset any_chunk_delete_option = o.delete_corrupted or o.delete_wrong_located or o.delete_entities or o.delete_shared_offset any_region_replace_option = o.replace_too_small any_region_delete_option = o.delete_too_small error = parser.error # All scanners will use this progress bar widgets = ['Scanning: ', FractionWidget(), ' ', progressbar.Percentage(), ' ', progressbar.Bar(left='[', right=']'), ' ', progressbar.ETA()] if o.interactive or o.summary: if any_chunk_replace_option or any_region_replace_option: error('Can\'t use the options --replace-* , --delete-* and ' '--log with --interactive. You can choose all this ' 'while in the interactive mode.') else: # Not options.interactive if o.backups: if not any_chunk_replace_option and not any_region_replace_option: error('The option --backups needs at least one of the ' '--replace-* options') else: if (len(regionset.regions) > 0): error('You can\'t use the replace options while scanning ' 'sparate region files. The input should be only one ' 'world and you intruduced {0} individual region ' 'files.'.format(len(regionset.regions))) elif (len(world_list) > 1): error('You can\'t use the replace options while scanning ' 'multiple worlds. The input should be only one ' 'world and you intruduced {0} ' 'worlds.'.format(len(world_list))) if not o.backups and any_chunk_replace_option: error("The options --replace-* need the --backups option") if o.entity_limit < 0: error("The entity limit must be at least 0!") print("\nWelcome to Region Fixer!") print("(version: {0})".format(parser.version)) # Do things with the option options args # Create a list of worlds containing the backups of the region files if o.backups: backup_worlds = parse_backup_list(o.backups) if not backup_worlds: print ('[WARNING] No valid backup directories found, won\'t fix ' 'any chunk.') else: backup_worlds = [] # The program starts if o.interactive: c = InteractiveLoop(world_list, regionset, o, backup_worlds) c.cmdloop() else: summary_text = "" # Scan the separate region files if len(regionset.regions) > 0: console_scan_regionset(regionset, o.processes, o.entity_limit, o.delete_entities, o.verbose) print(regionset.generate_report(True)) # Delete chunks delete_bad_chunks(options, regionset) # Delete region files delete_bad_regions(options, regionset) # Verbose log if options.summary: summary_text += "\n" summary_text += entitle("Separate region files") summary_text += "\n" t = regionset.summary() if t: summary_text += t else: summary_text += "No problems found.\n\n" # scan all the world folders for w in world_list: w_name = w.get_name() print(entitle(' Scanning world: {0} '.format(w_name), 0)) console_scan_world(w, o.processes, o.entity_limit, o.delete_entities, o.verbose) print("") print(entitle('Scan results for: {0}'.format(w_name), 0)) print(w.generate_report(True)) # corrupted, wrong_located, entities_prob, shared_prob,\ # total_chunks, too_small_region, unreadable_region, total_regions\ # = w.generate_report(standalone = False) print("") # Replace chunks if backup_worlds and not len(world_list) > 1: del_ent = options.delete_entities ent_lim = options.entity_limit options_replace = [o.replace_corrupted, o.replace_wrong_located, o.replace_entities, o.replace_shared_offset] replacing = zip(options_replace, world.CHUNK_PROBLEMS_ITERATOR) for replace, (problem, status, arg) in replacing: if replace: total = w.count_chunks(problem) if total: text = " Replacing chunks with status: {0} ".format(status) print("{0:#^60}".format(text)) fixed = w.replace_problematic_chunks(backup_worlds, problem, ent_lim, del_ent) print("\n{0} replaced of a total of {1} chunks with status: {2}".format(fixed, total, status)) else: print("No chunks to replace with status: {0}".format(status)) elif any_chunk_replace_option and not backup_worlds: print("Info: Won't replace any chunk.") print("No backup worlds found, won't replace any chunks/region files!") elif any_chunk_replace_option and backup_worlds and len(world_list) > 1: print("Info: Won't replace any chunk.") print("Can't use the replace options while scanning more than one world!") # replace region files if backup_worlds and not len(world_list) > 1: del_ent = options.delete_entities ent_lim = options.entity_limit options_replace = [o.replace_too_small] replacing = zip(options_replace, world.REGION_PROBLEMS_ITERATOR) for replace, (problem, status, arg) in replacing: if replace: total = w.count_regions(problem) if total: text = " Replacing regions with status: {0} ".format(status) print("{0:#^60}".format(text)) fixed = w.replace_problematic_regions(backup_worlds, problem, ent_lim, del_ent) print("\n{0} replaced of a total of {1} regions with status: {2}".format(fixed, total, status)) else: print("No region to replace with status: {0}".format(status)) elif any_region_replace_option and not backup_worlds: print("Info: Won't replace any regions.") print("No valid backup worlds found, won't replace any chunks/region files!") print("Note: You probably inserted some backup worlds with the backup option but they are probably no valid worlds, the most common issue is wrong path.") elif any_region_replace_option and backup_worlds and len(world_list) > 1: print("Info: Won't replace any regions.") print("Can't use the replace options while scanning more than one world!") # delete chunks delete_bad_chunks(options, w) # delete region files delete_bad_regions(options, w) # print a summary for this world if options.summary: summary_text += w.summary() # verbose log text if options.summary == '-': print("\nPrinting log:\n") print(summary_text) elif options.summary != None: try: f = open(options.summary, 'w') f.write(summary_text) f.write('\n') f.close() print("Log file saved in \'{0}\'.".format(options.summary)) except: print("Something went wrong while saving the log file!") return 0
def main(): usage = ('%(prog)s [options] <world-path> ' '<other-world-path> ... <region-files> ...') epilog = ('Copyright (C) 2020 Alejandro Aguilera (Fenixin)\n' 'https://github.com/Fenixin/Minecraft-Region-Fixer\n' 'This program comes with ABSOLUTELY NO WARRANTY; for ' 'details see COPYING.txt. This is free software, and you ' 'are welcome to redistribute it under certain conditions; ' 'see COPYING.txt for details.') parser = argparse.ArgumentParser( description=('Program to check the integrity of ' 'Minecraft worlds and fix them when ' 'possible. It uses NBT by twoolie. ' 'Author: Alejandro Aguilera (Fenixin)'), prog='region_fixer', usage=usage, epilog=epilog) parser.add_argument( '--backups', '-b', help=('List of backup directories of the Minecraft world ' 'to use to fix corrupted chunks and/or wrong located ' 'chunks. Warning! Region-Fixer is not going to check if' 'it\'s the same world, be careful! This argument can be a' ' comma separated list (but never with spaces between ' 'elements!). This option can be only used scanning one ' 'world.'), metavar='<backups>', type=str, dest='backups', default=None) parser.add_argument( '--replace-corrupted', '--rc', help='Try to replace the corrupted chunks using the backup' ' directories. Can be only used scanning one world.', default=False, dest='replace_corrupted', action='store_true') parser.add_argument( '--replace-wrong-located', '--rw', help='Try to replace the wrong located chunks using the ' 'backup directories. Can be only used scanning one ' 'world.', default=False, dest='replace_wrong_located', action='store_true') parser.add_argument( '--replace-entities', '--re', help='Try to replace the chunks with too many entities using ' 'the backup directories. Can be only used scanning ' 'one world.', default=False, dest='replace_entities', action='store_true') parser.add_argument( '--replace-shared-offset', '--rs', help='Try to replace the chunks with a shared offset using ' 'the backup directories. Can be only used scanning ' 'one world.', default=False, dest='replace_shared_offset', action='store_true') parser.add_argument( '--replace-too-small', '--rt', help='Try to replace the region files that are too small to ' 'be actually be a region file using the backup directories.' 'Can be only used scanning one world.', default=False, dest='replace_too_small', action='store_true') parser.add_argument( '--delete-corrupted', '--dc', help='[WARNING!] This option deletes! Delete all the corrupted ' 'chunks. Used with --replace-corrupted or --replace-wrong-located' ' will delete all the non-replaced chunks.', action='store_true', default=False) parser.add_argument( '--delete-wrong-located', '--dw', help='[WARNING!] This option deletes! Delete all the wrong located ' 'chunks. Used with --replace-corrupted or --replace-wrong-located' ' will delete all the non-replaced chunks.', action='store_true', default=False, dest='delete_wrong_located') parser.add_argument('--delete-entities', '--de', help='[WARNING!] This option deletes! Delete ALL ' 'the entities in chunks with more entities than ' '--entity-limit (300 by default). In a Minecraft ' 'entities are mostly mobs and items dropped in the ' 'ground, items in chests and other stuff won\'t be ' 'touched. Read the README for more info. Region-Fixer ' 'will delete the entities while scanning so you can ' 'stop and resume the process', action='store_true', default=False, dest='delete_entities') parser.add_argument( '--delete-shared-offset', '--ds', help='[WARNING!] This option deletes! Delete all the chunk ' 'with status shared offset. It will remove the region ' 'header for the false chunk, note that you ' 'don\'t loose any chunk doing this.', action='store_true', default=False, dest='delete_shared_offset') parser.add_argument( '--delete-missing-tag', '--dmt', help='[WARNING!] This option deletes! Remove any chunks ' 'with the mandatory entities tag missing.', dest='delete_missing_tag', default=False, action='store_true') parser.add_argument( '--fix-corrupted', '--fc', help='Try to fix chunks that are corrupted by extracting as much ' 'information as possible', dest='fix_corrupted', default=False, action='store_true') parser.add_argument( '--fix-missing-tag', '--fm', help='Fix chunks that have the Entities tag missing. This will add ' 'the missing tag.', dest='fix_missing_tag', default=False, action='store_true') parser.add_argument( '--fix-wrong-located', '--fw', help= 'Fix chunks that are wrong located. This will save them in the coordinates ' 'stored in their data.', dest='fix_wrong_located', default=False, action='store_true') parser.add_argument( '--delete-too-small', '--dt', help='[WARNING!] This option deletes! Remove any region files ' 'found to be too small to actually be a region file.', dest='delete_too_small', default=False, action='store_true') parser.add_argument( '--entity-limit', '--el', help='Specify the limit for the --delete-entities option ' '(default = 300).', dest='entity_limit', default=300, action='store', type=int) parser.add_argument( '--processes', '-p', help='Set the number of workers to use for scanning. (default ' '= 1, not use multiprocessing at all)', action='store', type=int, default=1) status_abbr = "" for status in c.CHUNK_PROBLEMS: status_abbr += "{0}: {1}; ".format(c.CHUNK_PROBLEMS_ABBR[status], c.CHUNK_STATUS_TEXT[status]) parser.add_argument( '--verbose', '-v', help=('Don\'t use a progress bar, instead print a line per ' 'scanned file with results information. The ' 'letters mean:\n') + status_abbr, action='store_true', default=False) #=========================================================================== # parser.add_argument('--interactive', # '-i', # help='Enter in interactive mode, where you can scan, see the ' # 'problems, and fix them in a terminal like mode', # dest='interactive', # default=False, # action='store_true', ) #=========================================================================== parser.add_argument( '--log', '-l', help='Save a log of all the problems found in the specified ' 'file. The log file contains all the problems found with ' 'this information: region file, chunk coordinates and ' 'problem. Use \'-\' as name to show the log at the end ' 'of the scan.', type=str, default=None, dest='summary') parser.add_argument('paths', help='List with world or region paths', nargs='*') args = parser.parse_args() if sys.version_info[0] != 3: print("") print("Minecraft Region Fixer only works with python 3.x") print(("(And you just tried to run it in python {0})".format( sys.version))) print("") return c.RV_CRASH if is_bare_console(): print("") print("Minecraft Region Fixer is a command line application and \n" "you have just double clicked it. If you really want to run \n" "the command line interface you have to use a command prompt.\n" "Run cmd.exe in the run window.\n\n") print("") getpass("Press enter to continue:") return c.RV_CRASH world_list, regionset = world.parse_paths(args.paths) # print greetings an version number print("\nWelcome to Region Fixer!") print(("(v {0})".format(version_string))) # Check if there are valid worlds to scan if not (world_list or regionset): print('Error: No worlds or region files to scan! Use ' '--help for a complete list of options.') return c.RV_NOTHING_TO_SCAN # Check basic options compatibilities any_chunk_replace_option = args.replace_corrupted or \ args.replace_wrong_located or \ args.replace_entities or \ args.replace_shared_offset any_region_replace_option = args.replace_too_small if False or args.summary: # removed interactive mode args.interactive if any_chunk_replace_option or any_region_replace_option: parser.error( 'Error: Can\'t use the options --replace-* , --delete-* with ' '--log') else: # Not options.interactive if args.backups: if not any_chunk_replace_option and not any_region_replace_option: parser.error( 'Error: The option --backups needs at least one of the ' '--replace-* options') else: if len(regionset) > 0: parser.error( 'Error: You can\'t use the replace options while scanning ' 'separate region files. The input should be only one ' 'world and you introduced {0} individual region ' 'files.'.format(len(regionset))) elif len(world_list) > 1: parser.error( 'Error: You can\'t use the replace options while scanning ' 'multiple worlds. The input should be only one ' 'world and you introduced {0} ' 'worlds.'.format(len(world_list))) if not args.backups and any_chunk_replace_option: parser.error( "Error: The options --replace-* need the --backups option") if args.entity_limit < 0: parser.error("Error: The entity limit must be at least 0!") # Do things with the option options args # Create a list of worlds containing the backups of the region files if args.backups: backup_worlds = world.parse_backup_list(args.backups) if not backup_worlds: print('[WARNING] No valid backup directories found, won\'t fix ' 'any chunk.') else: backup_worlds = [] # The scanning process starts found_problems_in_regionsets = False found_problems_in_worlds = False if False: # removed args.interactive ci = InteractiveLoop(world_list, regionset, args, backup_worlds) ci.cmdloop() return c.RV_OK else: summary_text = "" # Scan the separate region files if len(regionset) > 0: console_scan_regionset(regionset, args.processes, args.entity_limit, args.delete_entities, args.verbose) print((regionset.generate_report(True))) # Delete chunks delete_bad_chunks(args, regionset) # Delete region files delete_bad_regions(args, regionset) # fix chunks fix_bad_chunks(args, regionset) # Verbose log if args.summary: summary_text += "\n" summary_text += entitle("Separate region files") summary_text += "\n" t = regionset.summary() if t: summary_text += t else: summary_text += "No problems found.\n\n" # Check if problems have been found if regionset.has_problems: found_problems_in_regionsets = True # scan all the world folders for w in world_list: w_name = w.get_name() print((entitle(' Scanning world: {0} '.format(w_name), 0))) console_scan_world(w, args.processes, args.entity_limit, args.delete_entities, args.verbose) print("") print((entitle('Scan results for: {0}'.format(w_name), 0))) print((w.generate_report(True))) print("") # Replace chunks if backup_worlds and len(world_list) <= 1: del_ent = args.delete_entities ent_lim = args.entity_limit options_replace = [ args.replace_corrupted, args.replace_wrong_located, args.replace_entities, args.replace_shared_offset ] replacing = list( zip(options_replace, c.CHUNK_PROBLEMS_ITERATOR)) for replace, (problem, status, arg) in replacing: if replace: total = w.count_chunks(problem) if total: text = " Replacing chunks with status: {0} ".format( status) print(("{0:#^60}".format(text))) fixed = w.replace_problematic_chunks( backup_worlds, problem, ent_lim, del_ent) print(( "\n{0} replaced of a total of {1} chunks with status: {2}" .format(fixed, total, status))) else: print(("No chunks to replace with status: {0}". format(status))) elif any_chunk_replace_option and not backup_worlds: print("Info: Won't replace any chunk.") print( "No backup worlds found, won't replace any chunks/region files!" ) elif any_chunk_replace_option and backup_worlds and len( world_list) > 1: print("Info: Won't replace any chunk.") print( "Can't use the replace options while scanning more than one world!" ) # replace region files if backup_worlds and len(world_list) <= 1: del_ent = args.delete_entities ent_lim = args.entity_limit options_replace = [args.replace_too_small] replacing = list( zip(options_replace, c.REGION_PROBLEMS_ITERATOR)) for replace, (problem, status, arg) in replacing: if replace: total = w.count_regions(problem) if total: text = " Replacing regions with status: {0} ".format( status) print(("{0:#^60}".format(text))) fixed = w.replace_problematic_regions( backup_worlds, problem, ent_lim, del_ent) print(( "\n{0} replaced of a total of {1} regions with status: {2}" .format(fixed, total, status))) else: print(("No region to replace with status: {0}". format(status))) elif any_region_replace_option and not backup_worlds: print("Info: Won't replace any regions.") print( "No valid backup worlds found, won't replace any chunks/region files!" ) print( "Note: You probably inserted some backup worlds with the backup option but they are probably no valid worlds, the most common issue is wrong path." ) elif any_region_replace_option and backup_worlds and len( world_list) > 1: print("Info: Won't replace any regions.") print( "Can't use the replace options while scanning more than one world!" ) # delete chunks delete_bad_chunks(args, w) # delete region files delete_bad_regions(args, w) # fix chunks fix_bad_chunks(args, w) # print a summary for this world if args.summary: summary_text += w.summary() # check if problems have been found if w.has_problems: found_problems_in_worlds = True # verbose log text if args.summary == '-': print("\nPrinting log:\n") print(summary_text) elif args.summary is not None: try: f = open(args.summary, 'w') f.write(summary_text) f.write('\n') f.close() print(("Log file saved in \'{0}\'.".format(args.summary))) except: print("Something went wrong while saving the log file!") if found_problems_in_regionsets or found_problems_in_worlds: return c.RV_BAD_WORLD return c.RV_OK
def main(): usage = ('usage: \n%prog [options] <world-path> ' '<other-world-path> ... <region-files> ...') epilog = ('Copyright (C) 2011 Alejandro Aguilera (Fenixin)\n' 'https://github.com/Fenixin/Minecraft-Region-Fixer\n' 'This program comes with ABSOLUTELY NO WARRANTY; for ' 'details see COPYING.txt. This is free software, and you ' 'are welcome to redistribute it under certain conditions; ' 'see COPYING.txt for details.') parser = OptionParser(description=('Program to check the integrity of ' 'Minecraft worlds and fix them when ' 'possible. It uses NBT by twoolie. ' 'Author: Alejandro Aguilera (Fenixin)'), prog='region_fixer', version=version_string, usage=usage, epilog=epilog) add_option = parser.add_option add_option('--backups', '-b', help=('List of backup directories of the Minecraft world ' 'to use to fix corrupted chunks and/or wrong located ' 'chunks. Warning! Region-Fixer is not going to check if' 'it\'s the same world, be careful! This argument can be a' ' comma separated list (but never with spaces between ' 'elements!). This option can be only used scanning one ' 'world.'), metavar='<backups>', type=str, dest='backups', default=None) add_option('--replace-corrupted', '--rc', help='Tries to replace the corrupted chunks using the backup' ' directories. This option can be only used scanning one' ' world.', default=False, dest='replace_corrupted', action='store_true') add_option('--replace-wrong-located', '--rw', help='Tries to replace the wrong located chunks using the ' 'backup directories. This option can be only used scanning' ' one world.', default=False, dest='replace_wrong_located', action='store_true') add_option('--replace-entities', '--re', help='Tries to replace the chunks with too many entities using ' 'the backup directories. This option can be only used ' 'scanning one world.', default=False, dest='replace_entities', action='store_true') add_option('--replace-shared-offset', '--rs', help='Tries to replace the chunks with a shared offset using ' 'the backup directories. This option can be only used' 'scanning one world.', default=False, dest='replace_shared_offset', action='store_true') add_option('--replace-too-small', '--rt', help='Tries to replace the region files that are too small to ' 'be actually be a region file using the backup ' 'directories. This option can be only used scanning one ' 'world.', default=False, dest='replace_too_small', action='store_true') add_option('--delete-corrupted', '--dc', help='[WARNING!] This option deletes! This option will delete ' 'all the corrupted chunks. Used with --replace-corrupted ' 'or --replace-wrong-located it will delete all the ' 'non-replaced chunks.', action='store_true', default=False) add_option('--delete-wrong-located', '--dw', help=('[WARNING!] This option deletes!' 'The same as --delete-corrupted but for wrong ' 'located chunks'), action='store_true', default=False, dest='delete_wrong_located') add_option('--delete-entities', '--de', help='[WARNING!] This option deletes! This option deletes ALL ' 'the entities in chunks with more entities than ' '--entity-limit (300 by default). In a Minecraft ' 'entities are mostly mobs and items dropped in the ' 'grond, items in chests and other stuff won\'t be ' 'touched. Read the README for more info. Region-Fixer ' 'will delete the entities while scanning so you can ' 'stop and resume the process', action='store_true', default=False, dest='delete_entities') add_option('--delete-shared-offset', '--ds', help='[WARNING!] This option deletes! This option will delete ' 'all the chunk with status shared offset. It will remove ' 'the region header for the false chunk, note that you ' 'don\'t loos any chunk doing this.', action='store_true', default=False, dest='delete_shared_offset') add_option('--delete-too-small', '--dt', help='[WARNING!] This option deletes! Removes any region files ' 'found to be too small to actually be a region file.', dest='delete_too_small', default=False, action='store_true') add_option('--entity-limit', '--el', help='Specify the limit for the --delete-entities option ' '(default = 300).', dest='entity_limit', default=300, action='store', type=int) add_option('--processes', '-p', help='Set the number of workers to use for scanning. (defaulta ' '= 1, not use multiprocessing at all)', action='store', type=int, default=1) add_option('--verbose', '-v', help='Don\'t use a progress bar, instead print a line per ' 'scanned region file with results information. The ' 'letters mean c: corrupted; w: wrong located; t: total of ' 'chunksm; tme: too many entities problem', action='store_true', default=False) add_option( '--interactive', '-i', help='Enter in interactive mode, where you can scan, see the ' 'problems, and fix them in a terminal like mode', dest='interactive', default=False, action='store_true', ) add_option('--log', '-l', help='Saves a log of all the problems found in the spicifyed ' 'file. The log file contains all the problems found with ' 'this information: region file, chunk coordinates and ' 'problem. Use \'-\' as name to show the log at the end ' 'of the scan.', type=str, default=None, dest='summary') (options, args) = parser.parse_args() o = options if sys.version_info[0] > 2: print("") print("Minecraft Region Fixer only works with python 2.x") print("(And you just tried to run it in python {0})".format( sys.version)) print("") return 1 if is_bare_console(): print("") print( "Minecraft Region Fixer hast a command line aplication and a GUI\n" "(Graphic User Interface) and you have just double clicked the\n" "command line interface. If you really want to run the command line\n" "interface you have to use a command prompt (cmd.exe)\n\n" "You can also run the gui, double click regionfixer_gui.py instead!" ) print("") getpass("Press enter to continue:") return 1 # Args are world_paths and region files if not args: parser.error('No world paths or region files specified! Use ' '--help for a complete list of options.') world_list, regionset = parse_paths(args) if not (world_list or regionset): print("Error: No worlds or region files to scan!") return 1 # Check basic options compatibilities any_chunk_replace_option = o.replace_corrupted or \ o.replace_wrong_located or \ o.replace_entities or \ o.replace_shared_offset any_chunk_delete_option = o.delete_corrupted or \ o.delete_wrong_located or \ o.delete_entities or \ o.delete_shared_offset any_region_replace_option = o.replace_too_small any_region_delete_option = o.delete_too_small error = parser.error # All scanners will use this progress bar widgets = [ 'Scanning: ', FractionWidget(), ' ', progressbar.Percentage(), ' ', progressbar.Bar(left='[', right=']'), ' ', progressbar.ETA() ] if o.interactive or o.summary: if any_chunk_replace_option or any_region_replace_option: error('Can\'t use the options --replace-* , --delete-* and ' '--log with --interactive. You can choose all this ' 'while in the interactive mode.') else: # Not options.interactive if o.backups: if not any_chunk_replace_option and not any_region_replace_option: error('The option --backups needs at least one of the ' '--replace-* options') else: if (len(regionset.regions) > 0): error('You can\'t use the replace options while scanning ' 'sparate region files. The input should be only one ' 'world and you intruduced {0} individual region ' 'files.'.format(len(regionset.regions))) elif (len(world_list) > 1): error('You can\'t use the replace options while scanning ' 'multiple worlds. The input should be only one ' 'world and you intruduced {0} ' 'worlds.'.format(len(world_list))) if not o.backups and any_chunk_replace_option: error("The options --replace-* need the --backups option") if o.entity_limit < 0: error("The entity limit must be at least 0!") print("\nWelcome to Region Fixer!") print("(version: {0})".format(parser.version)) # Do things with the option options args # Create a list of worlds containing the backups of the region files if o.backups: backup_worlds = parse_backup_list(o.backups) if not backup_worlds: print('[WARNING] No valid backup directories found, won\'t fix ' 'any chunk.') else: backup_worlds = [] # The program starts if o.interactive: c = InteractiveLoop(world_list, regionset, o, backup_worlds) c.cmdloop() else: summary_text = "" # Scan the separate region files if len(regionset.regions) > 0: console_scan_regionset(regionset, o.processes, o.entity_limit, o.delete_entities, o.verbose) print(regionset.generate_report(True)) # Delete chunks delete_bad_chunks(options, regionset) # Delete region files delete_bad_regions(options, regionset) # Verbose log if options.summary: summary_text += "\n" summary_text += entitle("Separate region files") summary_text += "\n" t = regionset.summary() if t: summary_text += t else: summary_text += "No problems found.\n\n" # scan all the world folders for w in world_list: w_name = w.get_name() print(entitle(' Scanning world: {0} '.format(w_name), 0)) console_scan_world(w, o.processes, o.entity_limit, o.delete_entities, o.verbose) print("") print(entitle('Scan results for: {0}'.format(w_name), 0)) print(w.generate_report(True)) # corrupted, wrong_located, entities_prob, shared_prob,\ # total_chunks, too_small_region, unreadable_region, total_regions\ # = w.generate_report(standalone = False) print("") # Replace chunks if backup_worlds and not len(world_list) > 1: del_ent = options.delete_entities ent_lim = options.entity_limit options_replace = [ o.replace_corrupted, o.replace_wrong_located, o.replace_entities, o.replace_shared_offset ] replacing = zip(options_replace, world.CHUNK_PROBLEMS_ITERATOR) for replace, (problem, status, arg) in replacing: if replace: total = w.count_chunks(problem) if total: text = " Replacing chunks with status: {0} ".format( status) print("{0:#^60}".format(text)) fixed = w.replace_problematic_chunks( backup_worlds, problem, ent_lim, del_ent) print( "\n{0} replaced of a total of {1} chunks with status: {2}" .format(fixed, total, status)) else: print( "No chunks to replace with status: {0}".format( status)) elif any_chunk_replace_option and not backup_worlds: print("Info: Won't replace any chunk.") print( "No backup worlds found, won't replace any chunks/region files!" ) elif any_chunk_replace_option and backup_worlds and len( world_list) > 1: print("Info: Won't replace any chunk.") print( "Can't use the replace options while scanning more than one world!" ) # replace region files if backup_worlds and not len(world_list) > 1: del_ent = options.delete_entities ent_lim = options.entity_limit options_replace = [o.replace_too_small] replacing = zip(options_replace, world.REGION_PROBLEMS_ITERATOR) for replace, (problem, status, arg) in replacing: if replace: total = w.count_regions(problem) if total: text = " Replacing regions with status: {0} ".format( status) print("{0:#^60}".format(text)) fixed = w.replace_problematic_regions( backup_worlds, problem, ent_lim, del_ent) print( "\n{0} replaced of a total of {1} regions with status: {2}" .format(fixed, total, status)) else: print( "No region to replace with status: {0}".format( status)) elif any_region_replace_option and not backup_worlds: print("Info: Won't replace any regions.") print( "No valid backup worlds found, won't replace any chunks/region files!" ) print( "Note: You probably inserted some backup worlds with the backup option but they are probably no valid worlds, the most common issue is wrong path." ) elif any_region_replace_option and backup_worlds and len( world_list) > 1: print("Info: Won't replace any regions.") print( "Can't use the replace options while scanning more than one world!" ) # delete chunks delete_bad_chunks(options, w) # delete region files delete_bad_regions(options, w) # print a summary for this world if options.summary: summary_text += w.summary() # verbose log text if options.summary == '-': print("\nPrinting log:\n") print(summary_text) elif options.summary != None: try: f = open(options.summary, 'w') f.write(summary_text) f.write('\n') f.close() print("Log file saved in \'{0}\'.".format(options.summary)) except: print("Something went wrong while saving the log file!") return 0