Skip to content

Commit fe599a1

Browse files
Berserker66el-u
authored andcommitted
Core: log fill progress (ArchipelagoMW#2382)
* Core: log fill progress * Add names to common fill steps * Update Fill.py Co-authored-by: el-u <[email protected]> * Apply suggestions from code review Co-authored-by: el-u <[email protected]> * cleanup default name --------- Co-authored-by: el-u <[email protected]>
1 parent e353738 commit fe599a1

File tree

3 files changed

+39
-12
lines changed

3 files changed

+39
-12
lines changed

Fill.py

+35-10
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ class FillError(RuntimeError):
1515
pass
1616

1717

18+
def _log_fill_progress(name: str, placed: int, total_items: int) -> None:
19+
logging.info(f"Current fill step ({name}) at {placed}/{total_items} items placed.")
20+
21+
1822
def sweep_from_pool(base_state: CollectionState, itempool: typing.Sequence[Item] = tuple()) -> CollectionState:
1923
new_state = base_state.copy()
2024
for item in itempool:
@@ -26,7 +30,7 @@ def sweep_from_pool(base_state: CollectionState, itempool: typing.Sequence[Item]
2630
def fill_restrictive(world: MultiWorld, base_state: CollectionState, locations: typing.List[Location],
2731
item_pool: typing.List[Item], single_player_placement: bool = False, lock: bool = False,
2832
swap: bool = True, on_place: typing.Optional[typing.Callable[[Location], None]] = None,
29-
allow_partial: bool = False, allow_excluded: bool = False) -> None:
33+
allow_partial: bool = False, allow_excluded: bool = False, name: str = "Unknown") -> None:
3034
"""
3135
:param world: Multiworld to be filled.
3236
:param base_state: State assumed before fill.
@@ -38,16 +42,20 @@ def fill_restrictive(world: MultiWorld, base_state: CollectionState, locations:
3842
:param on_place: callback that is called when a placement happens
3943
:param allow_partial: only place what is possible. Remaining items will be in the item_pool list.
4044
:param allow_excluded: if true and placement fails, it is re-attempted while ignoring excluded on Locations
45+
:param name: name of this fill step for progress logging purposes
4146
"""
4247
unplaced_items: typing.List[Item] = []
4348
placements: typing.List[Location] = []
4449
cleanup_required = False
45-
4650
swapped_items: typing.Counter[typing.Tuple[int, str, bool]] = Counter()
4751
reachable_items: typing.Dict[int, typing.Deque[Item]] = {}
4852
for item in item_pool:
4953
reachable_items.setdefault(item.player, deque()).append(item)
5054

55+
# for progress logging
56+
total = min(len(item_pool), len(locations))
57+
placed = 0
58+
5159
while any(reachable_items.values()) and locations:
5260
# grab one item per player
5361
items_to_place = [items.pop()
@@ -152,9 +160,15 @@ def fill_restrictive(world: MultiWorld, base_state: CollectionState, locations:
152160
spot_to_fill.locked = lock
153161
placements.append(spot_to_fill)
154162
spot_to_fill.event = item_to_place.advancement
163+
placed += 1
164+
if not placed % 1000:
165+
_log_fill_progress(name, placed, total)
155166
if on_place:
156167
on_place(spot_to_fill)
157168

169+
if total > 1000:
170+
_log_fill_progress(name, placed, total)
171+
158172
if cleanup_required:
159173
# validate all placements and remove invalid ones
160174
state = sweep_from_pool(base_state, [])
@@ -198,6 +212,8 @@ def remaining_fill(world: MultiWorld,
198212
unplaced_items: typing.List[Item] = []
199213
placements: typing.List[Location] = []
200214
swapped_items: typing.Counter[typing.Tuple[int, str]] = Counter()
215+
total = min(len(itempool), len(locations))
216+
placed = 0
201217
while locations and itempool:
202218
item_to_place = itempool.pop()
203219
spot_to_fill: typing.Optional[Location] = None
@@ -247,6 +263,12 @@ def remaining_fill(world: MultiWorld,
247263

248264
world.push_item(spot_to_fill, item_to_place, False)
249265
placements.append(spot_to_fill)
266+
placed += 1
267+
if not placed % 1000:
268+
_log_fill_progress("Remaining", placed, total)
269+
270+
if total > 1000:
271+
_log_fill_progress("Remaining", placed, total)
250272

251273
if unplaced_items and locations:
252274
# There are leftover unplaceable items and locations that won't accept them
@@ -282,7 +304,7 @@ def accessibility_corrections(world: MultiWorld, state: CollectionState, locatio
282304
locations.append(location)
283305
if pool and locations:
284306
locations.sort(key=lambda loc: loc.progress_type != LocationProgressType.PRIORITY)
285-
fill_restrictive(world, state, locations, pool)
307+
fill_restrictive(world, state, locations, pool, name="Accessibility Corrections")
286308

287309

288310
def inaccessible_location_rules(world: MultiWorld, state: CollectionState, locations):
@@ -352,23 +374,25 @@ def distribute_early_items(world: MultiWorld,
352374
player_local = early_local_rest_items[player]
353375
fill_restrictive(world, base_state,
354376
[loc for loc in early_locations if loc.player == player],
355-
player_local, lock=True, allow_partial=True)
377+
player_local, lock=True, allow_partial=True, name=f"Local Early Items P{player}")
356378
if player_local:
357379
logging.warning(f"Could not fulfill rules of early items: {player_local}")
358380
early_rest_items.extend(early_local_rest_items[player])
359381
early_locations = [loc for loc in early_locations if not loc.item]
360-
fill_restrictive(world, base_state, early_locations, early_rest_items, lock=True, allow_partial=True)
382+
fill_restrictive(world, base_state, early_locations, early_rest_items, lock=True, allow_partial=True,
383+
name="Early Items")
361384
early_locations += early_priority_locations
362385
for player in world.player_ids:
363386
player_local = early_local_prog_items[player]
364387
fill_restrictive(world, base_state,
365388
[loc for loc in early_locations if loc.player == player],
366-
player_local, lock=True, allow_partial=True)
389+
player_local, lock=True, allow_partial=True, name=f"Local Early Progression P{player}")
367390
if player_local:
368391
logging.warning(f"Could not fulfill rules of early items: {player_local}")
369392
early_prog_items.extend(player_local)
370393
early_locations = [loc for loc in early_locations if not loc.item]
371-
fill_restrictive(world, base_state, early_locations, early_prog_items, lock=True, allow_partial=True)
394+
fill_restrictive(world, base_state, early_locations, early_prog_items, lock=True, allow_partial=True,
395+
name="Early Progression")
372396
unplaced_early_items = early_rest_items + early_prog_items
373397
if unplaced_early_items:
374398
logging.warning("Ran out of early locations for early items. Failed to place "
@@ -422,13 +446,14 @@ def mark_for_locking(location: Location):
422446

423447
if prioritylocations:
424448
# "priority fill"
425-
fill_restrictive(world, world.state, prioritylocations, progitempool, swap=False, on_place=mark_for_locking)
449+
fill_restrictive(world, world.state, prioritylocations, progitempool, swap=False, on_place=mark_for_locking,
450+
name="Priority")
426451
accessibility_corrections(world, world.state, prioritylocations, progitempool)
427452
defaultlocations = prioritylocations + defaultlocations
428453

429454
if progitempool:
430-
# "progression fill"
431-
fill_restrictive(world, world.state, defaultlocations, progitempool)
455+
# "advancement/progression fill"
456+
fill_restrictive(world, world.state, defaultlocations, progitempool, name="Progression")
432457
if progitempool:
433458
raise FillError(
434459
f'Not enough locations for progress items. There are {len(progitempool)} more items than locations')

worlds/alttp/Dungeons.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,8 @@ def fill_dungeons_restrictive(multiworld: MultiWorld):
264264

265265
if loc in all_state_base.events:
266266
all_state_base.events.remove(loc)
267-
fill_restrictive(multiworld, all_state_base, locations, in_dungeon_items, True, True)
267+
fill_restrictive(multiworld, all_state_base, locations, in_dungeon_items, True, True,
268+
name="LttP Dungeon Items")
268269

269270

270271
dungeon_music_addresses = {'Eastern Palace - Prize': [0x1559A],

worlds/alttp/__init__.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,8 @@ def pre_fill(self):
470470
prizepool = unplaced_prizes.copy()
471471
prize_locs = empty_crystal_locations.copy()
472472
world.random.shuffle(prize_locs)
473-
fill_restrictive(world, all_state, prize_locs, prizepool, True, lock=True)
473+
fill_restrictive(world, all_state, prize_locs, prizepool, True, lock=True,
474+
name="LttP Dungeon Prizes")
474475
except FillError as e:
475476
lttp_logger.exception("Failed to place dungeon prizes (%s). Will retry %s more times", e,
476477
attempts - attempt)

0 commit comments

Comments
 (0)