some general improvements. Mostly performance improvements of patching roms in multiworld with enemizer
This commit is contained in:
		
							parent
							
								
									128be8df89
								
							
						
					
					
						commit
						6059db3ea0
					
				| 
						 | 
					@ -817,7 +817,8 @@ class Boss(object):
 | 
				
			||||||
        return self.defeat_rule(state, self.player)
 | 
					        return self.defeat_rule(state, self.player)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Location(object):
 | 
					class Location(object):
 | 
				
			||||||
    def __init__(self, player, name='', address=None, crystal=False, hint_text=None, parent=None, player_address=None):
 | 
					    def __init__(self, player: int, name: str = '', address=None, crystal=False, hint_text=None, parent=None,
 | 
				
			||||||
 | 
					                 player_address=None):
 | 
				
			||||||
        self.name = name
 | 
					        self.name = name
 | 
				
			||||||
        self.parent_region = parent
 | 
					        self.parent_region = parent
 | 
				
			||||||
        self.item = None
 | 
					        self.item = None
 | 
				
			||||||
| 
						 | 
					@ -825,7 +826,7 @@ class Location(object):
 | 
				
			||||||
        self.address = address
 | 
					        self.address = address
 | 
				
			||||||
        self.player_address = player_address
 | 
					        self.player_address = player_address
 | 
				
			||||||
        self.spot_type = 'Location'
 | 
					        self.spot_type = 'Location'
 | 
				
			||||||
        self.hint_text = hint_text if hint_text is not None else 'Hyrule'
 | 
					        self.hint_text: str = hint_text if hint_text else name
 | 
				
			||||||
        self.recursion_count = 0
 | 
					        self.recursion_count = 0
 | 
				
			||||||
        self.staleness_count = 0
 | 
					        self.staleness_count = 0
 | 
				
			||||||
        self.event = False
 | 
					        self.event = False
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										134
									
								
								Main.py
								
								
								
								
							
							
						
						
									
										134
									
								
								Main.py
								
								
								
								
							| 
						 | 
					@ -154,65 +154,83 @@ def main(args, seed=None):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    rom_names = []
 | 
					    rom_names = []
 | 
				
			||||||
    jsonout = {}
 | 
					    jsonout = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _gen_rom(team: int, player: int):
 | 
				
			||||||
 | 
					        sprite_random_on_hit = type(args.sprite[player]) is str and args.sprite[player].lower() == 'randomonhit'
 | 
				
			||||||
 | 
					        use_enemizer = (world.boss_shuffle[player] != 'none' or world.enemy_shuffle[player] != 'none'
 | 
				
			||||||
 | 
					                        or world.enemy_health[player] != 'default' or world.enemy_damage[player] != 'default'
 | 
				
			||||||
 | 
					                        or args.shufflepots[player] or sprite_random_on_hit)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        rom = JsonRom() if args.jsonout or use_enemizer else LocalRom(args.rom, extendedmsu=args.extendedmsu[player])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        patch_rom(world, rom, player, team, use_enemizer)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if use_enemizer and (args.enemizercli or not args.jsonout):
 | 
				
			||||||
 | 
					            patch_enemizer(world, player, rom, args.rom, args.enemizercli, args.shufflepots[player],
 | 
				
			||||||
 | 
					                           sprite_random_on_hit, extendedmsu=args.extendedmsu[player])
 | 
				
			||||||
 | 
					            if not args.jsonout:
 | 
				
			||||||
 | 
					                rom = LocalRom.fromJsonRom(rom, args.rom, 0x400000, args.extendedmsu[player])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if args.race:
 | 
				
			||||||
 | 
					            patch_race_rom(rom)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        world.spoiler.hashes[(player, team)] = get_hash_string(rom.hash)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        apply_rom_settings(rom, args.heartbeep[player], args.heartcolor[player], args.quickswap[player],
 | 
				
			||||||
 | 
					                           args.fastmenu[player], args.disablemusic[player], args.sprite[player],
 | 
				
			||||||
 | 
					                           args.ow_palettes[player], args.uw_palettes[player])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if args.jsonout:
 | 
				
			||||||
 | 
					            jsonout[f'patch_t{team}_p{player}'] = rom.patches
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            mcsb_name = ''
 | 
				
			||||||
 | 
					            if all([world.mapshuffle[player], world.compassshuffle[player], world.keyshuffle[player],
 | 
				
			||||||
 | 
					                    world.bigkeyshuffle[player]]):
 | 
				
			||||||
 | 
					                mcsb_name = '-keysanity'
 | 
				
			||||||
 | 
					            elif [world.mapshuffle[player], world.compassshuffle[player], world.keyshuffle[player],
 | 
				
			||||||
 | 
					                  world.bigkeyshuffle[player]].count(True) == 1:
 | 
				
			||||||
 | 
					                mcsb_name = '-mapshuffle' if world.mapshuffle[player] else '-compassshuffle' if world.compassshuffle[
 | 
				
			||||||
 | 
					                    player] else '-keyshuffle' if world.keyshuffle[player] else '-bigkeyshuffle'
 | 
				
			||||||
 | 
					            elif any([world.mapshuffle[player], world.compassshuffle[player], world.keyshuffle[player],
 | 
				
			||||||
 | 
					                      world.bigkeyshuffle[player]]):
 | 
				
			||||||
 | 
					                mcsb_name = '-%s%s%s%sshuffle' % (
 | 
				
			||||||
 | 
					                    'M' if world.mapshuffle[player] else '', 'C' if world.compassshuffle[player] else '',
 | 
				
			||||||
 | 
					                    'S' if world.keyshuffle[player] else '', 'B' if world.bigkeyshuffle[player] else '')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            outfilepname = f'_T{team + 1}' if world.teams > 1 else ''
 | 
				
			||||||
 | 
					            if world.players > 1:
 | 
				
			||||||
 | 
					                outfilepname += f'_P{player}'
 | 
				
			||||||
 | 
					            if world.players > 1 or world.teams > 1:
 | 
				
			||||||
 | 
					                outfilepname += f"_{world.player_names[player][team].replace(' ', '_')}" if world.player_names[player][
 | 
				
			||||||
 | 
					                                                                                                team] != 'Player %d' % player else ''
 | 
				
			||||||
 | 
					            outfilesuffix = ('_%s_%s-%s-%s-%s%s_%s-%s%s%s%s%s' % (world.logic[player], world.difficulty[player],
 | 
				
			||||||
 | 
					                                                                  world.difficulty_adjustments[player],
 | 
				
			||||||
 | 
					                                                                  world.mode[player], world.goal[player],
 | 
				
			||||||
 | 
					                                                                  "" if world.timer[player] in [False,
 | 
				
			||||||
 | 
					                                                                                                'display'] else "-" +
 | 
				
			||||||
 | 
					                                                                                                                world.timer[
 | 
				
			||||||
 | 
					                                                                                                                    player],
 | 
				
			||||||
 | 
					                                                                  world.shuffle[player], world.algorithm,
 | 
				
			||||||
 | 
					                                                                  mcsb_name,
 | 
				
			||||||
 | 
					                                                                  "-retro" if world.retro[player] else "",
 | 
				
			||||||
 | 
					                                                                  "-prog_" + world.progressive[player] if
 | 
				
			||||||
 | 
					                                                                  world.progressive[player] in ['off',
 | 
				
			||||||
 | 
					                                                                                                'random'] else "",
 | 
				
			||||||
 | 
					                                                                  "-nohints" if not world.hints[
 | 
				
			||||||
 | 
					                                                                      player] else "")) if not args.outputname else ''
 | 
				
			||||||
 | 
					            rom.write_to_file(output_path(f'{outfilebase}{outfilepname}{outfilesuffix}.sfc'))
 | 
				
			||||||
 | 
					        return (player, team, list(rom.name))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if not args.suppress_rom:
 | 
					    if not args.suppress_rom:
 | 
				
			||||||
        for team in range(world.teams):
 | 
					        import concurrent.futures
 | 
				
			||||||
            for player in range(1, world.players + 1):
 | 
					        futures = []
 | 
				
			||||||
                sprite_random_on_hit = type(args.sprite[player]) is str and args.sprite[player].lower() == 'randomonhit'
 | 
					        with concurrent.futures.ThreadPoolExecutor() as pool:
 | 
				
			||||||
                use_enemizer = (world.boss_shuffle[player] != 'none' or world.enemy_shuffle[player] != 'none'
 | 
					            for team in range(world.teams):
 | 
				
			||||||
                                or world.enemy_health[player] != 'default' or world.enemy_damage[player] != 'default'
 | 
					                for player in range(1, world.players + 1):
 | 
				
			||||||
                                or args.shufflepots[player] or sprite_random_on_hit)
 | 
					                    futures.append(pool.submit(_gen_rom, team, player))
 | 
				
			||||||
 | 
					        for future in futures:
 | 
				
			||||||
                rom = JsonRom() if args.jsonout or use_enemizer else LocalRom(args.rom, extendedmsu=args.extendedmsu[player])
 | 
					            rom_name = future.result()
 | 
				
			||||||
 | 
					            rom_names.append(rom_name)
 | 
				
			||||||
                patch_rom(world, rom, player, team, use_enemizer)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if use_enemizer and (args.enemizercli or not args.jsonout):
 | 
					 | 
				
			||||||
                    patch_enemizer(world, player, rom, args.rom, args.enemizercli, args.shufflepots[player], sprite_random_on_hit, extendedmsu=args.extendedmsu[player])
 | 
					 | 
				
			||||||
                    if not args.jsonout:
 | 
					 | 
				
			||||||
                        rom = LocalRom.fromJsonRom(rom, args.rom, 0x400000, args.extendedmsu[player])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if args.race:
 | 
					 | 
				
			||||||
                    patch_race_rom(rom)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                rom_names.append((player, team, list(rom.name)))
 | 
					 | 
				
			||||||
                world.spoiler.hashes[(player, team)] = get_hash_string(rom.hash)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                apply_rom_settings(rom, args.heartbeep[player], args.heartcolor[player], args.quickswap[player], args.fastmenu[player], args.disablemusic[player], args.sprite[player], args.ow_palettes[player], args.uw_palettes[player])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if args.jsonout:
 | 
					 | 
				
			||||||
                    jsonout[f'patch_t{team}_p{player}'] = rom.patches
 | 
					 | 
				
			||||||
                else:
 | 
					 | 
				
			||||||
                    mcsb_name = ''
 | 
					 | 
				
			||||||
                    if all([world.mapshuffle[player], world.compassshuffle[player], world.keyshuffle[player], world.bigkeyshuffle[player]]):
 | 
					 | 
				
			||||||
                        mcsb_name = '-keysanity'
 | 
					 | 
				
			||||||
                    elif [world.mapshuffle[player], world.compassshuffle[player], world.keyshuffle[player], world.bigkeyshuffle[player]].count(True) == 1:
 | 
					 | 
				
			||||||
                        mcsb_name = '-mapshuffle' if world.mapshuffle[player] else '-compassshuffle' if world.compassshuffle[player] else '-keyshuffle' if world.keyshuffle[player] else '-bigkeyshuffle'
 | 
					 | 
				
			||||||
                    elif any([world.mapshuffle[player], world.compassshuffle[player], world.keyshuffle[player], world.bigkeyshuffle[player]]):
 | 
					 | 
				
			||||||
                        mcsb_name = '-%s%s%s%sshuffle' % (
 | 
					 | 
				
			||||||
                        'M' if world.mapshuffle[player] else '', 'C' if world.compassshuffle[player] else '',
 | 
					 | 
				
			||||||
                        'S' if world.keyshuffle[player] else '', 'B' if world.bigkeyshuffle[player] else '')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    outfilepname = f'_T{team+1}' if world.teams > 1 else ''
 | 
					 | 
				
			||||||
                    if world.players > 1:
 | 
					 | 
				
			||||||
                        outfilepname += f'_P{player}'
 | 
					 | 
				
			||||||
                    if world.players > 1 or world.teams > 1:
 | 
					 | 
				
			||||||
                        outfilepname += f"_{world.player_names[player][team].replace(' ', '_')}" if world.player_names[player][team] != 'Player %d' % player else ''
 | 
					 | 
				
			||||||
                    outfilesuffix = ('_%s_%s-%s-%s-%s%s_%s-%s%s%s%s%s' % (world.logic[player], world.difficulty[player],
 | 
					 | 
				
			||||||
                                                                          world.difficulty_adjustments[player],
 | 
					 | 
				
			||||||
                                                                          world.mode[player], world.goal[player],
 | 
					 | 
				
			||||||
                                                                          "" if world.timer[player] in [False,
 | 
					 | 
				
			||||||
                                                                                                        'display'] else "-" +
 | 
					 | 
				
			||||||
                                                                                                                        world.timer[
 | 
					 | 
				
			||||||
                                                                                                                            player],
 | 
					 | 
				
			||||||
                                                                          world.shuffle[player], world.algorithm,
 | 
					 | 
				
			||||||
                                                                          mcsb_name,
 | 
					 | 
				
			||||||
                                                                          "-retro" if world.retro[player] else "",
 | 
					 | 
				
			||||||
                                                                          "-prog_" + world.progressive[player] if
 | 
					 | 
				
			||||||
                                                                          world.progressive[player] in ['off',
 | 
					 | 
				
			||||||
                                                                                                        'random'] else "",
 | 
					 | 
				
			||||||
                                                                          "-nohints" if not world.hints[player] else "")) if not args.outputname else ''
 | 
					 | 
				
			||||||
                    rom.write_to_file(output_path(f'{outfilebase}{outfilepname}{outfilesuffix}.sfc'))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        multidata = zlib.compress(json.dumps({"names": parsed_names,
 | 
					        multidata = zlib.compress(json.dumps({"names": parsed_names,
 | 
				
			||||||
                                              "roms": rom_names,
 | 
					                                              "roms": rom_names,
 | 
				
			||||||
                                              "remote_items": [player for player in range(1, world.players + 1) if
 | 
					                                              "remote_items": [player for player in range(1, world.players + 1) if
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										19
									
								
								Regions.py
								
								
								
								
							
							
						
						
									
										19
									
								
								Regions.py
								
								
								
								
							| 
						 | 
					@ -296,19 +296,23 @@ def create_regions(world, player):
 | 
				
			||||||
    world.initialize_regions()
 | 
					    world.initialize_regions()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def create_lw_region(player, name, locations=None, exits=None):
 | 
					def create_lw_region(player: int, name: str, locations=None, exits=None):
 | 
				
			||||||
    return _create_region(player, name, RegionType.LightWorld, 'Light World', locations, exits)
 | 
					    return _create_region(player, name, RegionType.LightWorld, 'Light World', locations, exits)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def create_dw_region(player, name, locations=None, exits=None):
 | 
					
 | 
				
			||||||
 | 
					def create_dw_region(player: int, name: str, locations=None, exits=None):
 | 
				
			||||||
    return _create_region(player, name, RegionType.DarkWorld, 'Dark World', locations, exits)
 | 
					    return _create_region(player, name, RegionType.DarkWorld, 'Dark World', locations, exits)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def create_cave_region(player, name, hint='Hyrule', locations=None, exits=None):
 | 
					
 | 
				
			||||||
 | 
					def create_cave_region(player: int, name: str, hint: str, locations=None, exits=None):
 | 
				
			||||||
    return _create_region(player, name, RegionType.Cave, hint, locations, exits)
 | 
					    return _create_region(player, name, RegionType.Cave, hint, locations, exits)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def create_dungeon_region(player, name, hint='Hyrule', locations=None, exits=None):
 | 
					
 | 
				
			||||||
 | 
					def create_dungeon_region(player: int, name: str, hint: str, locations=None, exits=None):
 | 
				
			||||||
    return _create_region(player, name, RegionType.Dungeon, hint, locations, exits)
 | 
					    return _create_region(player, name, RegionType.Dungeon, hint, locations, exits)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _create_region(player, name, type, hint='Hyrule', locations=None, exits=None):
 | 
					
 | 
				
			||||||
 | 
					def _create_region(player: int, name: str, type: RegionType, hint: str, locations=None, exits=None):
 | 
				
			||||||
    ret = Region(name, type, hint, player)
 | 
					    ret = Region(name, type, hint, player)
 | 
				
			||||||
    if locations is None:
 | 
					    if locations is None:
 | 
				
			||||||
        locations = []
 | 
					        locations = []
 | 
				
			||||||
| 
						 | 
					@ -322,7 +326,8 @@ def _create_region(player, name, type, hint='Hyrule', locations=None, exits=None
 | 
				
			||||||
        ret.locations.append(Location(player, location, address, crystal, hint_text, ret, player_address))
 | 
					        ret.locations.append(Location(player, location, address, crystal, hint_text, ret, player_address))
 | 
				
			||||||
    return ret
 | 
					    return ret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def mark_light_world_regions(world, player):
 | 
					
 | 
				
			||||||
 | 
					def mark_light_world_regions(world, player: int):
 | 
				
			||||||
    # cross world caves may have some sections marked as both in_light_world, and in_dark_work.
 | 
					    # cross world caves may have some sections marked as both in_light_world, and in_dark_work.
 | 
				
			||||||
    # That is ok. the bunny logic will check for this case and incorporate special rules.
 | 
					    # That is ok. the bunny logic will check for this case and incorporate special rules.
 | 
				
			||||||
    queue = collections.deque(region for region in world.get_regions(player) if region.type == RegionType.LightWorld)
 | 
					    queue = collections.deque(region for region in world.get_regions(player) if region.type == RegionType.LightWorld)
 | 
				
			||||||
| 
						 | 
					@ -352,7 +357,7 @@ def mark_light_world_regions(world, player):
 | 
				
			||||||
                queue.append(exit.connected_region)
 | 
					                queue.append(exit.connected_region)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def create_shops(world, player):
 | 
					def create_shops(world, player: int):
 | 
				
			||||||
    for region_name, (room_id, type, shopkeeper, custom, locked, inventory) in shop_table.items():
 | 
					    for region_name, (room_id, type, shopkeeper, custom, locked, inventory) in shop_table.items():
 | 
				
			||||||
        if world.mode[player] == 'inverted' and region_name == 'Dark Lake Hylia Shop':
 | 
					        if world.mode[player] == 'inverted' and region_name == 'Dark Lake Hylia Shop':
 | 
				
			||||||
            locked = True
 | 
					            locked = True
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										12
									
								
								Rom.py
								
								
								
								
							
							
						
						
									
										12
									
								
								Rom.py
								
								
								
								
							| 
						 | 
					@ -159,11 +159,12 @@ def read_rom(stream):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def patch_enemizer(world, player, rom, baserom_path, enemizercli, shufflepots, random_sprite_on_hit, extendedmsu):
 | 
					def patch_enemizer(world, player, rom, baserom_path, enemizercli, shufflepots, random_sprite_on_hit, extendedmsu):
 | 
				
			||||||
    baserom_path = os.path.abspath(baserom_path)
 | 
					    baserom_path = os.path.abspath(baserom_path)
 | 
				
			||||||
    basepatch_path = os.path.abspath(local_path('data/base2current.json') if not extendedmsu else local_path('data/base2current_extendedmsu.json'))
 | 
					    basepatch_path = os.path.abspath(
 | 
				
			||||||
 | 
					        local_path('data/base2current.json') if not extendedmsu else local_path('data/base2current_extendedmsu.json'))
 | 
				
			||||||
    enemizer_basepatch_path = os.path.join(os.path.dirname(enemizercli), "enemizerBasePatch.json")
 | 
					    enemizer_basepatch_path = os.path.join(os.path.dirname(enemizercli), "enemizerBasePatch.json")
 | 
				
			||||||
    randopatch_path = os.path.abspath(output_path('enemizer_randopatch.json'))
 | 
					    randopatch_path = os.path.abspath(output_path(f'enemizer_randopatch_{player}.json'))
 | 
				
			||||||
    options_path = os.path.abspath(output_path('enemizer_options.json'))
 | 
					    options_path = os.path.abspath(output_path(f'enemizer_options_{player}.json'))
 | 
				
			||||||
    enemizer_output_path = os.path.abspath(output_path('enemizer_output.json'))
 | 
					    enemizer_output_path = os.path.abspath(output_path(f'enemizer_output_{player}.json'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # write options file for enemizer
 | 
					    # write options file for enemizer
 | 
				
			||||||
    options = {
 | 
					    options = {
 | 
				
			||||||
| 
						 | 
					@ -171,7 +172,8 @@ def patch_enemizer(world, player, rom, baserom_path, enemizercli, shufflepots, r
 | 
				
			||||||
        'RandomizeEnemiesType': 3,
 | 
					        'RandomizeEnemiesType': 3,
 | 
				
			||||||
        'RandomizeBushEnemyChance': world.enemy_shuffle[player] == 'chaos',
 | 
					        'RandomizeBushEnemyChance': world.enemy_shuffle[player] == 'chaos',
 | 
				
			||||||
        'RandomizeEnemyHealthRange': world.enemy_health[player] != 'default',
 | 
					        'RandomizeEnemyHealthRange': world.enemy_health[player] != 'default',
 | 
				
			||||||
        'RandomizeEnemyHealthType': {'default': 0, 'easy': 0, 'normal': 1, 'hard': 2, 'expert': 3}[world.enemy_health[player]],
 | 
					        'RandomizeEnemyHealthType': {'default': 0, 'easy': 0, 'normal': 1, 'hard': 2, 'expert': 3}[
 | 
				
			||||||
 | 
					            world.enemy_health[player]],
 | 
				
			||||||
        'OHKO': False,
 | 
					        'OHKO': False,
 | 
				
			||||||
        'RandomizeEnemyDamage': world.enemy_damage[player] != 'default',
 | 
					        'RandomizeEnemyDamage': world.enemy_damage[player] != 'default',
 | 
				
			||||||
        'AllowEnemyZeroDamage': True,
 | 
					        'AllowEnemyZeroDamage': True,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue