def resolve_settings(settings, window=dummy_window()): logger = logging.getLogger('') old_tricks = settings.allowed_tricks settings.load_distribution() # compare pointers to lists rather than contents, so even if the two are identical # we'll still log the error and note the dist file overrides completely. if old_tricks and old_tricks is not settings.allowed_tricks: logger.error( 'Tricks are set in two places! Using only the tricks from the distribution file.' ) for trick in logic_tricks.values(): settings.__dict__[ trick['name']] = trick['name'] in settings.allowed_tricks # we load the rom before creating the seed so that errors get caught early if settings.compress_rom == 'None' and not settings.create_spoiler: raise Exception( '`No Output` must have spoiler enabled to produce anything.') if settings.compress_rom not in ['None', 'Temp']: window.update_status('Loading ROM') rom = Rom(settings.rom) else: rom = None if not settings.world_count: settings.world_count = 1 elif settings.world_count < 1 or settings.world_count > 255: raise Exception('World Count must be between 1 and 255') # Bounds-check the player_num settings, in case something's gone wrong we want to know. if settings.player_num < 1: raise Exception( f'Invalid player num: {settings.player_num}; must be between (1, {settings.world_count})' ) if settings.player_num > settings.world_count: if settings.compress_rom not in ['None', 'Patch', 'Temp']: raise Exception( f'Player Num is {settings.player_num}; must be between (1, {settings.world_count})' ) settings.player_num = settings.world_count # Set to a custom hint distribution if plando is overriding the distro if len(settings.hint_dist_user) != 0: settings.hint_dist = 'custom' logger.info('OoT Randomizer Version %s - Seed: %s', __version__, settings.seed) settings.remove_disabled() logger.info('(Original) Settings string: %s\n', settings.settings_string) random.seed(settings.numeric_seed) settings.resolve_random_settings(cosmetic=False) logger.debug(settings.get_settings_display()) return rom
def main(settings, window=dummy_window()): start = time.process_time() logger = logging.getLogger('') worlds = [] for trick in logic_tricks.values(): settings.__dict__[ trick['name']] = trick['name'] in settings.allowed_tricks settings.load_distribution() # we load the rom before creating the seed so that error get caught early if settings.compress_rom == 'None' and not settings.create_spoiler: raise Exception( '`No Output` must have spoiler enabled to produce anything.') if settings.compress_rom != 'None': window.update_status('Loading ROM') rom = Rom(settings.rom) else: rom = None if not settings.world_count: settings.world_count = 1 if settings.world_count < 1 or settings.world_count > 255: raise Exception('World Count must be between 1 and 255') if settings.player_num > settings.world_count or settings.player_num < 1: if settings.compress_rom not in ['None', 'Patch']: raise Exception('Player Num must be between 1 and %d' % settings.world_count) else: settings.player_num = 1 logger.info('OoT Randomizer Version %s - Seed: %s', __version__, settings.seed) settings.remove_disabled() logger.info('(Original) Settings string: %s\n', settings.settings_string) random.seed(settings.numeric_seed) settings.resolve_random_settings(cosmetic=False) logger.debug(settings.get_settings_display()) max_attempts = 1 for attempt in range(1, max_attempts + 1): try: spoiler = generate(settings, window) break except ShuffleError as e: logger.warning('Failed attempt %d of %d: %s', attempt, max_attempts, e) if attempt >= max_attempts: raise else: logger.info('Retrying...\n\n') return patch_and_output(settings, window, spoiler, rom, start)
def main(settings, window=dummy_window()): start = time.process_time() logger = logging.getLogger('') worlds = [] allowed_tricks = {} for trick in logic_tricks.values(): settings.__dict__[ trick['name']] = trick['name'] in settings.allowed_tricks settings.load_distribution() # we load the rom before creating the seed so that error get caught early if settings.compress_rom == 'None' and not settings.create_spoiler: raise Exception( '`No Output` must have spoiler enabled to produce anything.') if settings.compress_rom != 'None': window.update_status('Loading ROM') rom = Rom(settings.rom) if not settings.world_count: settings.world_count = 1 if settings.world_count < 1 or settings.world_count > 255: raise Exception('World Count must be between 1 and 255') if settings.player_num > settings.world_count or settings.player_num < 1: if settings.compress_rom not in ['None', 'Patch']: raise Exception('Player Num must be between 1 and %d' % settings.world_count) else: settings.player_num = 1 logger.info('OoT Randomizer Version %s - Seed: %s\n\n', __version__, settings.seed) settings.remove_disabled() random.seed(settings.numeric_seed) settings.resolve_random_settings() for i in range(0, settings.world_count): worlds.append(World(settings)) window.update_status('Creating the Worlds') for id, world in enumerate(worlds): world.id = id world.distribution = settings.distribution.world_dists[id] logger.info('Generating World %d.' % id) window.update_progress(0 + 1 * (id + 1) / settings.world_count) logger.info('Creating Overworld') # Determine MQ Dungeons dungeon_pool = list(world.dungeon_mq) dist_num_mq = world.distribution.configure_dungeons( world, dungeon_pool) if world.mq_dungeons_random: for dungeon in dungeon_pool: world.dungeon_mq[dungeon] = random.choice([True, False]) world.mq_dungeons = list(world.dungeon_mq.values()).count(True) else: mqd_picks = random.sample(dungeon_pool, world.mq_dungeons - dist_num_mq) for dung in mqd_picks: world.dungeon_mq[dung] = True if settings.logic_rules == 'glitched': overworld_data = os.path.join(data_path('Glitched World'), 'Overworld.json') else: overworld_data = os.path.join(data_path('World'), 'Overworld.json') world.load_regions_from_json(overworld_data) create_dungeons(world) if settings.shopsanity != 'off': world.random_shop_prices() world.set_scrub_prices() window.update_progress(0 + 4 * (id + 1) / settings.world_count) logger.info('Calculating Access Rules.') set_rules(world) window.update_progress(0 + 5 * (id + 1) / settings.world_count) logger.info('Generating Item Pool.') generate_itempool(world) set_shop_rules(world) set_drop_location_names(world) logger.info('Setting Entrances.') set_entrances(worlds) window.update_status('Placing the Items') logger.info('Fill the world.') distribute_items_restrictive(window, worlds) window.update_progress(35) spoiler = Spoiler(worlds) cosmetics_log = None if settings.create_spoiler: window.update_status('Calculating Spoiler Data') logger.info('Calculating playthrough.') create_playthrough(spoiler) window.update_progress(50) if settings.create_spoiler or settings.hints != 'none': window.update_status('Calculating Hint Data') State.update_required_items(spoiler) for world in worlds: world.update_useless_areas(spoiler) buildGossipHints(spoiler, world) window.update_progress(55) spoiler.build_file_hash() logger.info('Patching ROM.') settings_string_hash = hashlib.sha1( settings.settings_string.encode('utf-8')).hexdigest().upper()[:5] if settings.output_file: outfilebase = settings.output_file elif settings.world_count > 1: outfilebase = 'OoT_%s_%s_W%d' % (settings_string_hash, settings.seed, settings.world_count) else: outfilebase = 'OoT_%s_%s' % (settings_string_hash, settings.seed) output_dir = default_output_path(settings.output_dir) if settings.compress_rom == 'Patch': rng_state = random.getstate() file_list = [] window.update_progress(65) for world in worlds: if settings.world_count > 1: window.update_status('Patching ROM: Player %d' % (world.id + 1)) patchfilename = '%sP%d.zpf' % (outfilebase, world.id + 1) else: window.update_status('Patching ROM') patchfilename = '%s.zpf' % outfilebase random.setstate(rng_state) patch_rom(spoiler, world, rom, outfilebase) cosmetics_log = patch_cosmetics(settings, rom) window.update_progress(65 + 20 * (world.id + 1) / settings.world_count) window.update_status('Creating Patch File') output_path = os.path.join(output_dir, patchfilename) file_list.append(patchfilename) create_patch_file(rom, output_path) rom.restore() window.update_progress(65 + 30 * (world.id + 1) / settings.world_count) if settings.create_cosmetics_log and cosmetics_log: window.update_status('Creating Cosmetics Log') if settings.world_count > 1: cosmetics_log_filename = "%sP%d_Cosmetics.txt" % ( outfilebase, world.id + 1) else: cosmetics_log_filename = '%s_Cosmetics.txt' % outfilebase cosmetics_log.to_file( os.path.join(output_dir, cosmetics_log_filename)) file_list.append(cosmetics_log_filename) cosmetics_log = None if settings.world_count > 1: window.update_status('Creating Patch Archive') output_path = os.path.join(output_dir, '%s.zpfz' % outfilebase) with zipfile.ZipFile(output_path, mode="w") as patch_archive: for file in file_list: file_path = os.path.join(output_dir, file) patch_archive.write(file_path, file.replace(outfilebase, ''), compress_type=zipfile.ZIP_DEFLATED) for file in file_list: os.remove(os.path.join(output_dir, file)) logger.info("Created patchfile at: %s" % output_path) window.update_progress(95) elif settings.compress_rom != 'None': window.update_status('Patching ROM') patch_rom(spoiler, worlds[settings.player_num - 1], rom, outfilebase) cosmetics_log = patch_cosmetics(settings, rom) window.update_progress(65) window.update_status('Saving Uncompressed ROM') if settings.world_count > 1: filename = "%sP%d.z64" % (outfilebase, settings.player_num) else: filename = '%s.z64' % outfilebase output_path = os.path.join(output_dir, filename) rom.write_to_file(output_path) if settings.compress_rom == 'True': window.update_status('Compressing ROM') logger.info('Compressing ROM.') if is_bundled(): compressor_path = "." else: compressor_path = "Compress" if platform.system() == 'Windows': if 8 * struct.calcsize("P") == 64: compressor_path += "\\Compress.exe" else: compressor_path += "\\Compress32.exe" elif platform.system() == 'Linux': if platform.uname()[4] == 'aarch64' or platform.uname( )[4] == 'arm64': compressor_path += "/Compress_ARM64" else: compressor_path += "/Compress" elif platform.system() == 'Darwin': compressor_path += "/Compress.out" else: compressor_path = "" logger.info('OS not supported for compression') output_compress_path = output_path[:output_path. rfind('.')] + '-comp.z64' if compressor_path != "": run_process( window, logger, [compressor_path, output_path, output_compress_path]) os.remove(output_path) logger.info("Created compessed rom at: %s" % output_compress_path) else: logger.info("Created uncompessed rom at: %s" % output_path) window.update_progress(95) for world in worlds: for info in setting_infos: world.settings.__dict__[info.name] = world.__dict__[info.name] settings.distribution.update_spoiler(spoiler) if settings.create_spoiler: window.update_status('Creating Spoiler Log') spoiler_path = os.path.join(output_dir, '%s_Spoiler.json' % outfilebase) settings.distribution.to_file(spoiler_path) logger.info("Created spoiler log at: %s" % ('%s_Spoiler.json' % outfilebase)) else: window.update_status('Creating Settings Log') settings_path = os.path.join(output_dir, '%s_Settings.json' % outfilebase) settings.distribution.to_file(settings_path) logger.info("Created settings log at: %s" % ('%s_Settings.json' % outfilebase)) if settings.create_cosmetics_log and cosmetics_log: window.update_status('Creating Cosmetics Log') if settings.world_count > 1 and not settings.output_file: filename = "%sP%d_Cosmetics.txt" % (outfilebase, settings.player_num) else: filename = '%s_Cosmetics.txt' % outfilebase cosmetic_path = os.path.join(output_dir, filename) cosmetics_log.to_file(cosmetic_path) logger.info("Created cosmetic log at: %s" % cosmetic_path) window.update_progress(100) if cosmetics_log and cosmetics_log.error: window.update_status( 'Success: Rom patched successfully. Some cosmetics could not be applied.' ) else: window.update_status('Success: Rom patched successfully') logger.info('Done. Enjoy.') logger.debug('Total Time: %s', time.process_time() - start) return worlds[settings.player_num - 1]
def main(settings, window=dummy_window()): start = time.process_time() logger = logging.getLogger('') old_tricks = settings.allowed_tricks settings.load_distribution() # compare pointers to lists rather than contents, so even if the two are identical # we'll still log the error and note the dist file overrides completely. if old_tricks and old_tricks is not settings.allowed_tricks: logger.error( 'Tricks are set in two places! Using only the tricks from the distribution file.' ) for trick in logic_tricks.values(): settings.__dict__[ trick['name']] = trick['name'] in settings.allowed_tricks # we load the rom before creating the seed so that errors get caught early if settings.compress_rom == 'None' and not settings.create_spoiler: raise Exception( '`No Output` must have spoiler enabled to produce anything.') if settings.compress_rom != 'None': window.update_status('Loading ROM') rom = Rom(settings.rom) else: rom = None if not settings.world_count: settings.world_count = 1 elif settings.world_count < 1 or settings.world_count > 255: raise Exception('World Count must be between 1 and 255') # Bounds-check the player_num settings, in case something's gone wrong we want to know. if settings.player_num < 1: raise Exception( f'Invalid player num: {settings.player_num}; must be between (1, {settings.world_count})' ) if settings.player_num > settings.world_count: if settings.compress_rom not in ['None', 'Patch']: raise Exception( f'Player Num is {settings.player_num}; must be between (1, {settings.world_count})' ) settings.player_num = settings.world_count logger.info('OoT Randomizer Version %s - Seed: %s', __version__, settings.seed) settings.remove_disabled() logger.info('(Original) Settings string: %s\n', settings.settings_string) random.seed(settings.numeric_seed) settings.resolve_random_settings(cosmetic=False) logger.debug(settings.get_settings_display()) max_attempts = 10 for attempt in range(1, max_attempts + 1): try: spoiler = generate(settings, window) break except ShuffleError as e: logger.warning('Failed attempt %d of %d: %s', attempt, max_attempts, e) if attempt >= max_attempts: raise else: logger.info('Retrying...\n\n') settings.reset_distribution() return patch_and_output(settings, window, spoiler, rom, start)