mirror of
https://github.com/MarioSpore/Grinch-AP.git
synced 2025-10-21 20:21:32 -06:00
Core: change Region caching to on_change from on-miss-strategy (#2366)
This commit is contained in:
@@ -195,7 +195,8 @@ class OOTWorld(World):
|
||||
setattr(self, option_name, option_value)
|
||||
|
||||
self.shop_prices = {}
|
||||
self.regions = [] # internal cache of regions for this world, used later
|
||||
self.regions = [] # internal caches of regions for this world, used later
|
||||
self._regions_cache = {}
|
||||
self.remove_from_start_inventory = [] # some items will be precollected but not in the inventory
|
||||
self.starting_items = Counter()
|
||||
self.songs_as_items = False
|
||||
@@ -526,6 +527,10 @@ class OOTWorld(World):
|
||||
# We still need to fill the location even if ALR is off.
|
||||
logger.debug('Unreachable location: %s', new_location.name)
|
||||
new_location.player = self.player
|
||||
# Change some attributes of Drop locations
|
||||
if new_location.type == 'Drop':
|
||||
new_location.name = new_region.name + ' ' + new_location.name
|
||||
new_location.show_in_spoiler = False
|
||||
new_region.locations.append(new_location)
|
||||
if 'events' in region:
|
||||
for event, rule in region['events'].items():
|
||||
@@ -555,7 +560,8 @@ class OOTWorld(World):
|
||||
|
||||
self.multiworld.regions.append(new_region)
|
||||
self.regions.append(new_region)
|
||||
self.multiworld._recache()
|
||||
self._regions_cache[new_region.name] = new_region
|
||||
# self.multiworld._recache()
|
||||
|
||||
def set_scrub_prices(self):
|
||||
# Get Deku Scrub Locations
|
||||
@@ -622,7 +628,7 @@ class OOTWorld(World):
|
||||
'Twinrova',
|
||||
'Links Pocket'
|
||||
)
|
||||
boss_rewards = [item for item in self.itempool if item.type == 'DungeonReward']
|
||||
boss_rewards = sorted(map(self.create_item, self.item_name_groups['rewards']))
|
||||
boss_locations = [self.multiworld.get_location(loc, self.player) for loc in boss_location_names]
|
||||
|
||||
placed_prizes = [loc.item.name for loc in boss_locations if loc.item is not None]
|
||||
@@ -636,7 +642,6 @@ class OOTWorld(World):
|
||||
item = prizepool.pop()
|
||||
loc = prize_locs.pop()
|
||||
loc.place_locked_item(item)
|
||||
self.multiworld.itempool.remove(item)
|
||||
self.hinted_dungeon_reward_locations[item.name] = loc
|
||||
|
||||
def create_item(self, name: str, allow_arbitrary_name: bool = False):
|
||||
@@ -671,7 +676,7 @@ class OOTWorld(World):
|
||||
self.multiworld.regions.append(menu)
|
||||
self.load_regions_from_json(overworld_data_path)
|
||||
self.load_regions_from_json(bosses_data_path)
|
||||
start.connect(self.multiworld.get_region('Root', self.player))
|
||||
start.connect(self.get_region('Root'))
|
||||
create_dungeons(self)
|
||||
self.parser.create_delayed_rules()
|
||||
|
||||
@@ -682,16 +687,11 @@ class OOTWorld(World):
|
||||
# Bind entrances to vanilla
|
||||
for region in self.regions:
|
||||
for exit in region.exits:
|
||||
exit.connect(self.multiworld.get_region(exit.vanilla_connected_region, self.player))
|
||||
exit.connect(self.get_region(exit.vanilla_connected_region))
|
||||
|
||||
def create_items(self):
|
||||
# Uniquely rename drop locations for each region and erase them from the spoiler
|
||||
set_drop_location_names(self)
|
||||
# Generate itempool
|
||||
generate_itempool(self)
|
||||
# Add dungeon rewards
|
||||
rewardlist = sorted(list(self.item_name_groups['rewards']))
|
||||
self.itempool += map(self.create_item, rewardlist)
|
||||
|
||||
junk_pool = get_junk_pool(self)
|
||||
removed_items = []
|
||||
@@ -769,7 +769,7 @@ class OOTWorld(World):
|
||||
|
||||
# Kill unreachable events that can't be gotten even with all items
|
||||
# Make sure to only kill actual internal events, not in-game "events"
|
||||
all_state = self.multiworld.get_all_state(False)
|
||||
all_state = self.multiworld.get_all_state(use_cache=True)
|
||||
all_locations = self.get_locations()
|
||||
reachable = self.multiworld.get_reachable_locations(all_state, self.player)
|
||||
unreachable = [loc for loc in all_locations if
|
||||
@@ -781,7 +781,6 @@ class OOTWorld(World):
|
||||
bigpoe = self.multiworld.get_location('Sell Big Poe from Market Guard House', self.player)
|
||||
if not all_state.has('Bottle with Big Poe', self.player) and bigpoe not in reachable:
|
||||
bigpoe.parent_region.locations.remove(bigpoe)
|
||||
self.multiworld.clear_location_cache()
|
||||
|
||||
# If fast scarecrow then we need to kill the Pierre location as it will be unreachable
|
||||
if self.free_scarecrow:
|
||||
@@ -997,6 +996,7 @@ class OOTWorld(World):
|
||||
fill_restrictive(multiworld, multiworld.get_all_state(False), locations, group_dungeon_items,
|
||||
single_player_placement=False, lock=True, allow_excluded=True)
|
||||
|
||||
|
||||
def generate_output(self, output_directory: str):
|
||||
if self.hints != 'none':
|
||||
self.hint_data_available.wait()
|
||||
@@ -1032,30 +1032,6 @@ class OOTWorld(World):
|
||||
player_name=self.multiworld.get_player_name(self.player))
|
||||
apz5.write()
|
||||
|
||||
# Write entrances to spoiler log
|
||||
all_entrances = self.get_shuffled_entrances()
|
||||
all_entrances.sort(reverse=True, key=lambda x: x.name)
|
||||
all_entrances.sort(reverse=True, key=lambda x: x.type)
|
||||
if not self.decouple_entrances:
|
||||
while all_entrances:
|
||||
loadzone = all_entrances.pop()
|
||||
if loadzone.type != 'Overworld':
|
||||
if loadzone.primary:
|
||||
entrance = loadzone
|
||||
else:
|
||||
entrance = loadzone.reverse
|
||||
if entrance.reverse is not None:
|
||||
self.multiworld.spoiler.set_entrance(entrance, entrance.replaces.reverse, 'both', self.player)
|
||||
else:
|
||||
self.multiworld.spoiler.set_entrance(entrance, entrance.replaces, 'entrance', self.player)
|
||||
else:
|
||||
reverse = loadzone.replaces.reverse
|
||||
if reverse in all_entrances:
|
||||
all_entrances.remove(reverse)
|
||||
self.multiworld.spoiler.set_entrance(loadzone, reverse, 'both', self.player)
|
||||
else:
|
||||
for entrance in all_entrances:
|
||||
self.multiworld.spoiler.set_entrance(entrance, entrance.replaces, 'entrance', self.player)
|
||||
|
||||
# Gathers hint data for OoT. Loops over all world locations for woth, barren, and major item locations.
|
||||
@classmethod
|
||||
@@ -1135,6 +1111,7 @@ class OOTWorld(World):
|
||||
for autoworld in multiworld.get_game_worlds("Ocarina of Time"):
|
||||
autoworld.hint_data_available.set()
|
||||
|
||||
|
||||
def fill_slot_data(self):
|
||||
self.collectible_flags_available.wait()
|
||||
return {
|
||||
@@ -1142,6 +1119,7 @@ class OOTWorld(World):
|
||||
'collectible_flag_offsets': self.collectible_flag_offsets
|
||||
}
|
||||
|
||||
|
||||
def modify_multidata(self, multidata: dict):
|
||||
|
||||
# Replace connect name
|
||||
@@ -1156,6 +1134,7 @@ class OOTWorld(World):
|
||||
continue
|
||||
multidata["precollected_items"][self.player].remove(item_id)
|
||||
|
||||
|
||||
def extend_hint_information(self, er_hint_data: dict):
|
||||
|
||||
er_hint_data[self.player] = {}
|
||||
@@ -1202,6 +1181,7 @@ class OOTWorld(World):
|
||||
er_hint_data[self.player][location.address] = main_entrance.name
|
||||
logger.debug(f"Set {location.name} hint data to {main_entrance.name}")
|
||||
|
||||
|
||||
def write_spoiler(self, spoiler_handle: typing.TextIO) -> None:
|
||||
required_trials_str = ", ".join(t for t in self.skipped_trials if not self.skipped_trials[t])
|
||||
spoiler_handle.write(f"\n\nTrials ({self.multiworld.get_player_name(self.player)}): {required_trials_str}\n")
|
||||
@@ -1211,6 +1191,32 @@ class OOTWorld(World):
|
||||
for k, v in self.shop_prices.items():
|
||||
spoiler_handle.write(f"{k}: {v} Rupees\n")
|
||||
|
||||
# Write entrances to spoiler log
|
||||
all_entrances = self.get_shuffled_entrances()
|
||||
all_entrances.sort(reverse=True, key=lambda x: x.name)
|
||||
all_entrances.sort(reverse=True, key=lambda x: x.type)
|
||||
if not self.decouple_entrances:
|
||||
while all_entrances:
|
||||
loadzone = all_entrances.pop()
|
||||
if loadzone.type != 'Overworld':
|
||||
if loadzone.primary:
|
||||
entrance = loadzone
|
||||
else:
|
||||
entrance = loadzone.reverse
|
||||
if entrance.reverse is not None:
|
||||
self.multiworld.spoiler.set_entrance(entrance, entrance.replaces.reverse, 'both', self.player)
|
||||
else:
|
||||
self.multiworld.spoiler.set_entrance(entrance, entrance.replaces, 'entrance', self.player)
|
||||
else:
|
||||
reverse = loadzone.replaces.reverse
|
||||
if reverse in all_entrances:
|
||||
all_entrances.remove(reverse)
|
||||
self.multiworld.spoiler.set_entrance(loadzone, reverse, 'both', self.player)
|
||||
else:
|
||||
for entrance in all_entrances:
|
||||
self.multiworld.spoiler.set_entrance(entrance, entrance.replaces, 'entrance', self.player)
|
||||
|
||||
|
||||
# Key ring handling:
|
||||
# Key rings are multiple items glued together into one, so we need to give
|
||||
# the appropriate number of keys in the collection state when they are
|
||||
@@ -1242,9 +1248,8 @@ class OOTWorld(World):
|
||||
return False
|
||||
|
||||
def get_shufflable_entrances(self, type=None, only_primary=False):
|
||||
return [entrance for entrance in self.multiworld.get_entrances() if (entrance.player == self.player and
|
||||
(type == None or entrance.type == type) and
|
||||
(not only_primary or entrance.primary))]
|
||||
return [entrance for entrance in self.multiworld.get_entrances(self.player) if (
|
||||
(type == None or entrance.type == type) and (not only_primary or entrance.primary))]
|
||||
|
||||
def get_shuffled_entrances(self, type=None, only_primary=False):
|
||||
return [entrance for entrance in self.get_shufflable_entrances(type=type, only_primary=only_primary) if
|
||||
@@ -1258,8 +1263,13 @@ class OOTWorld(World):
|
||||
def get_location(self, location):
|
||||
return self.multiworld.get_location(location, self.player)
|
||||
|
||||
def get_region(self, region):
|
||||
return self.multiworld.get_region(region, self.player)
|
||||
def get_region(self, region_name):
|
||||
try:
|
||||
return self._regions_cache[region_name]
|
||||
except KeyError:
|
||||
ret = self.multiworld.get_region(region_name, self.player)
|
||||
self._regions_cache[region_name] = ret
|
||||
return ret
|
||||
|
||||
def get_entrance(self, entrance):
|
||||
return self.multiworld.get_entrance(entrance, self.player)
|
||||
|
||||
Reference in New Issue
Block a user