Core: Region handling customization (#3682)
This commit is contained in:
		
							parent
							
								
									d3312287a8
								
							
						
					
					
						commit
						ceec51b9e1
					
				| 
						 | 
					@ -692,17 +692,25 @@ class CollectionState():
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def update_reachable_regions(self, player: int):
 | 
					    def update_reachable_regions(self, player: int):
 | 
				
			||||||
        self.stale[player] = False
 | 
					        self.stale[player] = False
 | 
				
			||||||
 | 
					        world: AutoWorld.World = self.multiworld.worlds[player]
 | 
				
			||||||
        reachable_regions = self.reachable_regions[player]
 | 
					        reachable_regions = self.reachable_regions[player]
 | 
				
			||||||
        blocked_connections = self.blocked_connections[player]
 | 
					 | 
				
			||||||
        queue = deque(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
 | 
					        # init on first call - this can't be done on construction since the regions don't exist yet
 | 
				
			||||||
        if start not in reachable_regions:
 | 
					        if start not in reachable_regions:
 | 
				
			||||||
            reachable_regions.add(start)
 | 
					            reachable_regions.add(start)
 | 
				
			||||||
            blocked_connections.update(start.exits)
 | 
					            self.blocked_connections[player].update(start.exits)
 | 
				
			||||||
            queue.extend(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
 | 
					        # run BFS on all connections, and keep track of those blocked by missing items
 | 
				
			||||||
        while queue:
 | 
					        while queue:
 | 
				
			||||||
            connection = queue.popleft()
 | 
					            connection = queue.popleft()
 | 
				
			||||||
| 
						 | 
					@ -722,6 +730,29 @@ class CollectionState():
 | 
				
			||||||
                    if new_entrance in blocked_connections and new_entrance not in queue:
 | 
					                    if new_entrance in blocked_connections and new_entrance not in queue:
 | 
				
			||||||
                        queue.append(new_entrance)
 | 
					                        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:
 | 
					    def copy(self) -> CollectionState:
 | 
				
			||||||
        ret = CollectionState(self.multiworld)
 | 
					        ret = CollectionState(self.multiworld)
 | 
				
			||||||
        ret.prog_items = {player: counter.copy() for player, counter in self.prog_items.items()}
 | 
					        ret.prog_items = {player: counter.copy() for player, counter in self.prog_items.items()}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -292,6 +292,14 @@ class World(metaclass=AutoWorldRegister):
 | 
				
			||||||
    web: ClassVar[WebWorld] = WebWorld()
 | 
					    web: ClassVar[WebWorld] = WebWorld()
 | 
				
			||||||
    """see WebWorld for options"""
 | 
					    """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"
 | 
					    multiworld: "MultiWorld"
 | 
				
			||||||
    """autoset on creation. The MultiWorld object for the currently generating multiworld."""
 | 
					    """autoset on creation. The MultiWorld object for the currently generating multiworld."""
 | 
				
			||||||
    player: int
 | 
					    player: int
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -101,6 +101,7 @@ class Factorio(World):
 | 
				
			||||||
    tech_tree_layout_prerequisites: typing.Dict[FactorioScienceLocation, typing.Set[FactorioScienceLocation]]
 | 
					    tech_tree_layout_prerequisites: typing.Dict[FactorioScienceLocation, typing.Set[FactorioScienceLocation]]
 | 
				
			||||||
    tech_mix: int = 0
 | 
					    tech_mix: int = 0
 | 
				
			||||||
    skip_silo: bool = False
 | 
					    skip_silo: bool = False
 | 
				
			||||||
 | 
					    origin_region_name = "Nauvis"
 | 
				
			||||||
    science_locations: typing.List[FactorioScienceLocation]
 | 
					    science_locations: typing.List[FactorioScienceLocation]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    settings: typing.ClassVar[FactorioSettings]
 | 
					    settings: typing.ClassVar[FactorioSettings]
 | 
				
			||||||
| 
						 | 
					@ -125,9 +126,6 @@ class Factorio(World):
 | 
				
			||||||
    def create_regions(self):
 | 
					    def create_regions(self):
 | 
				
			||||||
        player = self.player
 | 
					        player = self.player
 | 
				
			||||||
        random = self.multiworld.random
 | 
					        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)
 | 
					        nauvis = Region("Nauvis", player, self.multiworld)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        location_count = len(base_tech_table) - len(useless_technologies) - self.skip_silo + \
 | 
					        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)
 | 
					            event = FactorioItem(f"Automated {ingredient}", ItemClassification.progression, None, player)
 | 
				
			||||||
            location.place_locked_item(event)
 | 
					            location.place_locked_item(event)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        crash.connect(nauvis)
 | 
					        self.multiworld.regions.append(nauvis)
 | 
				
			||||||
        self.multiworld.regions += [menu, nauvis]
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def create_items(self) -> None:
 | 
					    def create_items(self) -> None:
 | 
				
			||||||
        player = self.player
 | 
					        player = self.player
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -45,7 +45,7 @@ class SubnauticaWorld(World):
 | 
				
			||||||
    options_dataclass = options.SubnauticaOptions
 | 
					    options_dataclass = options.SubnauticaOptions
 | 
				
			||||||
    options: options.SubnauticaOptions
 | 
					    options: options.SubnauticaOptions
 | 
				
			||||||
    required_client_version = (0, 5, 0)
 | 
					    required_client_version = (0, 5, 0)
 | 
				
			||||||
 | 
					    origin_region_name = "Planet 4546B"
 | 
				
			||||||
    creatures_to_scan: List[str]
 | 
					    creatures_to_scan: List[str]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def generate_early(self) -> None:
 | 
					    def generate_early(self) -> None:
 | 
				
			||||||
| 
						 | 
					@ -66,13 +66,9 @@ class SubnauticaWorld(World):
 | 
				
			||||||
            creature_pool, self.options.creature_scans.value)
 | 
					            creature_pool, self.options.creature_scans.value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def create_regions(self):
 | 
					    def create_regions(self):
 | 
				
			||||||
        # Create Regions
 | 
					        # Create Region
 | 
				
			||||||
        menu_region = Region("Menu", self.player, self.multiworld)
 | 
					 | 
				
			||||||
        planet_region = Region("Planet 4546B", self.player, self.multiworld)
 | 
					        planet_region = Region("Planet 4546B", self.player, self.multiworld)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Link regions together
 | 
					 | 
				
			||||||
        menu_region.connect(planet_region, "Lifepod 5")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # Create regular locations
 | 
					        # Create regular locations
 | 
				
			||||||
        location_names = itertools.chain((location["name"] for location in locations.location_table.values()),
 | 
					        location_names = itertools.chain((location["name"] for location in locations.location_table.values()),
 | 
				
			||||||
                                         (creature + creatures.suffix for creature in self.creatures_to_scan))
 | 
					                                         (creature + creatures.suffix for creature in self.creatures_to_scan))
 | 
				
			||||||
| 
						 | 
					@ -93,11 +89,8 @@ class SubnauticaWorld(World):
 | 
				
			||||||
                # make the goal event the victory "item"
 | 
					                # make the goal event the victory "item"
 | 
				
			||||||
                location.item.name = "Victory"
 | 
					                location.item.name = "Victory"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Register regions to multiworld
 | 
					        # Register region to multiworld
 | 
				
			||||||
        self.multiworld.regions += [
 | 
					        self.multiworld.regions.append(planet_region)
 | 
				
			||||||
            menu_region,
 | 
					 | 
				
			||||||
            planet_region
 | 
					 | 
				
			||||||
        ]
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # refer to rules.py
 | 
					    # refer to rules.py
 | 
				
			||||||
    set_rules = set_rules
 | 
					    set_rules = set_rules
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue