diff --git a/contrib/validateRegionFile.py b/contrib/validateRegionFile.py new file mode 100644 index 0000000..7dd2763 --- /dev/null +++ b/contrib/validateRegionFile.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python + +import os.path +import sys +overviewer_dir = os.path.split(os.path.split(os.path.abspath(__file__))[0])[0] +sys.path.insert(0, overviewer_dir) +import nbt + +def check_region(region_filename): + chunk_errors = [] + if not os.path.exists(region_filename): + raise Exception('Region file not found: %s' % region_filename) + try: + region = nbt.load_region(region_filename) + except IOError, e: + raise Exception('Error loading region (%s): %s' % (region_filename, e)) + try: + chunks = region.get_chunk_info(False) + except IOError, e: + raise Exception('Error reading region header (%s): %s' % (region_filename, e)) + except Exception, e: + raise Exception('Error reading region (%s): %s' % (region_filename, e)) + for x,y in chunks: + try: + check_chunk(region, x, y) + except Exception, e: + chunk_errors.append(e) + return (chunk_errors, len(chunks)) + +def check_chunk(region, x, y): + try: + data = region.load_chunk(x ,y) + except Exception, e: + raise Exception('Error reading chunk (%i, %i): %s' % (x, y, e)) + if data is None: + raise Exception('Chunk (%i, %i) is unexpectedly empty' % (x, y)) + else: + try: + processed_data = data.read_all() + except Exception, e: + raise Exception('Error reading chunk (%i, %i) data: %s' % (x, y, e)) + if processed_data == []: + raise Exception('Chunk (%i, %i) is an unexpectedly empty set' % (x, y)) + +if __name__ == '__main__': + try: + from optparse import OptionParser + + parser = OptionParser(usage='python contrib/%prog [OPTIONS] ', + description='This script will valide a minecraft region file for errors.') + parser.add_option('-v', dest='verbose', action='store_true', help='Print additional information.') + opts, args = parser.parse_args() + + region_files = [] + for path in args: + if os.path.isdir(path): + for dirpath, dirnames, filenames in os.walk(path, True): + for filename in filenames: + if filename.startswith('r.') and filename.endswith('.mcr'): + if filename not in region_files: + region_files.append(os.path.join(dirpath, filename)) + elif opts.verbose: + print('Ignoring non-region file: %s' % os.path.join(dirpath, filename)) + elif os.path.isfile(path): + dirpath,filename = os.path.split(path) + if filename.startswith('r.') and filename.endswith('.mcr'): + if path not in region_files: + region_files.append(path) + else: + print('Ignoring non-region file: %s' % path) + else: + if opts.verbose: + print('Ignoring arg: %s' % path) + if len(region_files) < 1: + print 'You must list at least one region file.' + parser.print_help() + sys.exit(1) + else: + overall_chunk_total = 0 + bad_chunk_total = 0 + bad_region_total = 0 + for region_file in region_files: + try: + (chunk_errors, region_chunks) = check_region(region_file) + bad_chunk_total += len(chunk_errors) + overall_chunk_total += region_chunks + except Exception, e: + bad_region_total += 1 + print('FAILED(%s): %s' % (region_file, e)) + else: + if len(chunk_errors) is not 0: + print('WARNING(%s) Chunks: %i/%' % (region_file, region_chunks - len(chunk_errors), region_chunks)) + if opts.verbose: + for error in chunk_errors: + print(error) + elif opts.verbose: + print ('PASSED(%s) Chunks: %i/%i' % (region_file, region_chunks - len(chunk_errors), region_chunks)) + if opts.verbose: + print 'REGIONS: %i/%i' % (len(region_files) - bad_region_total, len(region_files)) + print 'CHUNKS: %i/%i' % (overall_chunk_total - bad_chunk_total, overall_chunk_total) + except KeyboardInterrupt: + sys.exit(1) + except Exception, e: + print('ERROR: %s' % e) +