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