Core: Region handling customization (#3682)

This commit is contained in:
Fabian Dill 2024-09-05 16:32:45 +02:00 committed by GitHub
parent d3312287a8
commit ceec51b9e1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 48 additions and 19 deletions

View File

@ -692,17 +692,25 @@ class CollectionState():
def update_reachable_regions(self, player: int):
self.stale[player] = False
world: AutoWorld.World = self.multiworld.worlds[player]
reachable_regions = self.reachable_regions[player]
blocked_connections = self.blocked_connections[player]
queue = deque(self.blocked_connections[player])
start = self.multiworld.get_region("Menu", player)
start: Region = world.get_region(world.origin_region_name)
# init on first call - this can't be done on construction since the regions don't exist yet
if start not in reachable_regions:
reachable_regions.add(start)
blocked_connections.update(start.exits)
self.blocked_connections[player].update(start.exits)
queue.extend(start.exits)
if world.explicit_indirect_conditions:
self._update_reachable_regions_explicit_indirect_conditions(player, queue)
else:
self._update_reachable_regions_auto_indirect_conditions(player, queue)
def _update_reachable_regions_explicit_indirect_conditions(self, player: int, queue: deque):
reachable_regions = self.reachable_regions[player]
blocked_connections = self.blocked_connections[player]
# run BFS on all connections, and keep track of those blocked by missing items
while queue:
connection = queue.popleft()
@ -722,6 +730,29 @@ class CollectionState():
if new_entrance in blocked_connections and new_entrance not in queue:
queue.append(new_entrance)
def _update_reachable_regions_auto_indirect_conditions(self, player: int, queue: deque):
reachable_regions = self.reachable_regions[player]
blocked_connections = self.blocked_connections[player]
new_connection: bool = True
# run BFS on all connections, and keep track of those blocked by missing items
while new_connection:
new_connection = False
while queue:
connection = queue.popleft()
new_region = connection.connected_region
if new_region in reachable_regions:
blocked_connections.remove(connection)
elif connection.can_reach(self):
assert new_region, f"tried to search through an Entrance \"{connection}\" with no Region"
reachable_regions.add(new_region)
blocked_connections.remove(connection)
blocked_connections.update(new_region.exits)
queue.extend(new_region.exits)
self.path[new_region] = (new_region.name, self.path.get(connection, None))
new_connection = True
# sweep for indirect connections, mostly Entrance.can_reach(unrelated_Region)
queue.extend(blocked_connections)
def copy(self) -> CollectionState:
ret = CollectionState(self.multiworld)
ret.prog_items = {player: counter.copy() for player, counter in self.prog_items.items()}

View File

@ -292,6 +292,14 @@ class World(metaclass=AutoWorldRegister):
web: ClassVar[WebWorld] = WebWorld()
"""see WebWorld for options"""
origin_region_name: str = "Menu"
"""Name of the Region from which accessibility is tested."""
explicit_indirect_conditions: bool = True
"""If True, the world implementation is supposed to use MultiWorld.register_indirect_condition() correctly.
If False, everything is rechecked at every step, which is slower computationally,
but may be desirable in complex/dynamic worlds."""
multiworld: "MultiWorld"
"""autoset on creation. The MultiWorld object for the currently generating multiworld."""
player: int

View File

@ -101,6 +101,7 @@ class Factorio(World):
tech_tree_layout_prerequisites: typing.Dict[FactorioScienceLocation, typing.Set[FactorioScienceLocation]]
tech_mix: int = 0
skip_silo: bool = False
origin_region_name = "Nauvis"
science_locations: typing.List[FactorioScienceLocation]
settings: typing.ClassVar[FactorioSettings]
@ -125,9 +126,6 @@ class Factorio(World):
def create_regions(self):
player = self.player
random = self.multiworld.random
menu = Region("Menu", player, self.multiworld)
crash = Entrance(player, "Crash Land", menu)
menu.exits.append(crash)
nauvis = Region("Nauvis", player, self.multiworld)
location_count = len(base_tech_table) - len(useless_technologies) - self.skip_silo + \
@ -184,8 +182,7 @@ class Factorio(World):
event = FactorioItem(f"Automated {ingredient}", ItemClassification.progression, None, player)
location.place_locked_item(event)
crash.connect(nauvis)
self.multiworld.regions += [menu, nauvis]
self.multiworld.regions.append(nauvis)
def create_items(self) -> None:
player = self.player

View File

@ -45,7 +45,7 @@ class SubnauticaWorld(World):
options_dataclass = options.SubnauticaOptions
options: options.SubnauticaOptions
required_client_version = (0, 5, 0)
origin_region_name = "Planet 4546B"
creatures_to_scan: List[str]
def generate_early(self) -> None:
@ -66,13 +66,9 @@ class SubnauticaWorld(World):
creature_pool, self.options.creature_scans.value)
def create_regions(self):
# Create Regions
menu_region = Region("Menu", self.player, self.multiworld)
# Create Region
planet_region = Region("Planet 4546B", self.player, self.multiworld)
# Link regions together
menu_region.connect(planet_region, "Lifepod 5")
# Create regular locations
location_names = itertools.chain((location["name"] for location in locations.location_table.values()),
(creature + creatures.suffix for creature in self.creatures_to_scan))
@ -93,11 +89,8 @@ class SubnauticaWorld(World):
# make the goal event the victory "item"
location.item.name = "Victory"
# Register regions to multiworld
self.multiworld.regions += [
menu_region,
planet_region
]
# Register region to multiworld
self.multiworld.regions.append(planet_region)
# refer to rules.py
set_rules = set_rules