DS3: Convert post_fill to stage_post_fill for better performance (#4122)

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
This commit is contained in:
Mysteryem 2024-12-26 13:50:18 +00:00 committed by GitHub
parent 62942704bd
commit 33ae68c756
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 105 additions and 85 deletions

View File

@ -1366,7 +1366,8 @@ class DarkSouls3World(World):
text = "\n" + text + "\n"
spoiler_handle.write(text)
def post_fill(self):
@classmethod
def stage_post_fill(cls, multiworld: MultiWorld):
"""If item smoothing is enabled, rearrange items so they scale up smoothly through the run.
This determines the approximate order a given silo of items (say, soul items) show up in the
@ -1375,26 +1376,45 @@ class DarkSouls3World(World):
items, later spheres get higher-level ones. Within a sphere, items in DS3 are distributed in
region order, and then the best items in a sphere go into the multiworld.
"""
ds3_worlds = [world for world in cast(List[DarkSouls3World], multiworld.get_game_worlds(cls.game)) if
world.options.smooth_upgrade_items
or world.options.smooth_soul_items
or world.options.smooth_upgraded_weapons]
if not ds3_worlds:
# No worlds need item smoothing.
return
locations_by_sphere = [
sorted(loc for loc in sphere if loc.item.player == self.player and not loc.locked)
for sphere in self.multiworld.get_spheres()
]
spheres_per_player: Dict[int, List[List[Location]]] = {world.player: [] for world in ds3_worlds}
for sphere in multiworld.get_spheres():
locations_per_item_player: Dict[int, List[Location]] = {player: [] for player in spheres_per_player.keys()}
for location in sphere:
if location.locked:
continue
item_player = location.item.player
if item_player in locations_per_item_player:
locations_per_item_player[item_player].append(location)
for player, locations in locations_per_item_player.items():
# Sort for deterministic results.
locations.sort()
spheres_per_player[player].append(locations)
for ds3_world in ds3_worlds:
locations_by_sphere = spheres_per_player[ds3_world.player]
# All items in the base game in approximately the order they appear
all_item_order: List[DS3ItemData] = [
item_dictionary[location.default_item_name]
for region in region_order
# Shuffle locations within each region.
for location in self._shuffle(location_tables[region])
if self._is_location_available(location)
for location in ds3_world._shuffle(location_tables[region])
if ds3_world._is_location_available(location)
]
# All DarkSouls3Items for this world that have been assigned anywhere, grouped by name
full_items_by_name: Dict[str, List[DarkSouls3Item]] = defaultdict(list)
for location in self.multiworld.get_filled_locations():
if location.item.player == self.player and (
location.player != self.player or self._is_location_available(location)
for location in multiworld.get_filled_locations():
if location.item.player == ds3_world.player and (
location.player != ds3_world.player or ds3_world._is_location_available(location)
):
full_items_by_name[location.item.name].append(location.item)
@ -1441,17 +1461,17 @@ class DarkSouls3World(World):
locations = [loc for loc in sphere if loc.item.name in names]
# Check the game, not the player, because we know how to sort within regions for DS3
offworld = self._shuffle([loc for loc in locations if loc.game != "Dark Souls III"])
offworld = ds3_world._shuffle([loc for loc in locations if loc.game != "Dark Souls III"])
onworld = sorted((loc for loc in locations if loc.game == "Dark Souls III"),
key=lambda loc: loc.data.region_value)
# Give offworld regions the last (best) items within a given sphere
for location in onworld + offworld:
new_item = self._pop_item(location, converted_item_order)
new_item = ds3_world._pop_item(location, converted_item_order)
location.item = new_item
new_item.location = location
if self.options.smooth_upgrade_items:
if ds3_world.options.smooth_upgrade_items:
base_names = {
"Titanite Shard", "Large Titanite Shard", "Titanite Chunk", "Titanite Slab",
"Titanite Scale", "Twinkling Titanite", "Farron Coal", "Sage's Coal", "Giant's Coal",
@ -1459,17 +1479,17 @@ class DarkSouls3World(World):
}
smooth_items([item for item in all_item_order if item.base_name in base_names])
if self.options.smooth_soul_items:
if ds3_world.options.smooth_soul_items:
smooth_items([
item for item in all_item_order
if item.souls and item.classification != ItemClassification.progression
])
if self.options.smooth_upgraded_weapons:
if ds3_world.options.smooth_upgraded_weapons:
upgraded_weapons = [
location.item
for location in self.multiworld.get_filled_locations()
if location.item.player == self.player
for location in multiworld.get_filled_locations()
if location.item.player == ds3_world.player
and location.item.level and location.item.level > 0
and location.item.classification != ItemClassification.progression
]