2023-03-08 21:13:52 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								from . import Constants
							 | 
						
					
						
							
								
									
										
										
										
											2024-08-19 15:58:30 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								from typing import TYPE_CHECKING
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								if TYPE_CHECKING:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    from . import MinecraftWorld
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2023-03-08 21:13:52 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2024-08-19 15:58:30 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								def shuffle_structures(self: "MinecraftWorld") -> None:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    multiworld = self.multiworld
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    player = self.player
							 | 
						
					
						
							
								
									
										
										
										
											2023-03-08 21:13:52 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    default_connections = Constants.region_info["default_connections"]
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    illegal_connections = Constants.region_info["illegal_connections"]
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    # Get all unpaired exits and all regions without entrances (except the Menu)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    # This function is destructive on these lists. 
							 | 
						
					
						
							
								
									
										
										
										
											2024-08-19 15:58:30 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    exits = [exit.name for r in multiworld.regions if r.player == player for exit in r.exits if exit.connected_region is None]
							 | 
						
					
						
							
								
									
										
										
										
											2023-03-08 21:13:52 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    structs = [r.name for r in multiworld.regions if r.player == player and r.entrances == [] and r.name != 'Menu']
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    exits_spoiler = exits[:] # copy the original order for the spoiler log
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pairs = {}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    def set_pair(exit, struct): 
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (exit in exits) and (struct in structs) and (exit not in illegal_connections.get(struct, [])):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            pairs[exit] = struct
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            exits.remove(exit)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            structs.remove(struct)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        else: 
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            raise Exception(f"Invalid connection: {exit} => {struct} for player {player} ({multiworld.player_name[player]})")
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    # Connect plando structures first
							 | 
						
					
						
							
								
									
										
										
										
											2024-08-19 15:58:30 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if self.options.plando_connections:
							 | 
						
					
						
							
								
									
										
										
										
											2024-10-13 18:22:37 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        for conn in self.options.plando_connections:
							 | 
						
					
						
							
								
									
										
										
										
											2023-03-08 21:13:52 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            set_pair(conn.entrance, conn.exit)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    # The algorithm tries to place the most restrictive structures first. This algorithm always works on the
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    # relatively small set of restrictions here, but does not work on all possible inputs with valid configurations. 
							 | 
						
					
						
							
								
									
										
										
										
											2024-08-19 15:58:30 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if self.options.shuffle_structures:
							 | 
						
					
						
							
								
									
										
										
										
											2023-03-08 21:13:52 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        structs.sort(reverse=True, key=lambda s: len(illegal_connections.get(s, [])))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        for struct in structs[:]: 
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            try: 
							 | 
						
					
						
							
								
									
										
										
										
											2024-08-19 15:58:30 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                exit = self.random.choice([e for e in exits if e not in illegal_connections.get(struct, [])])
							 | 
						
					
						
							
								
									
										
										
										
											2023-03-08 21:13:52 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            except IndexError: 
							 | 
						
					
						
							
								
									
										
										
										
											2024-08-19 15:58:30 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                raise Exception(f"No valid structure placements remaining for player {player} ({self.player_name})")
							 | 
						
					
						
							
								
									
										
										
										
											2023-03-08 21:13:52 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            set_pair(exit, struct)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    else: # write remaining default connections
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        for (exit, struct) in default_connections: 
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if exit in exits: 
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                set_pair(exit, struct)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    # Make sure we actually paired everything; might fail if plando
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    try:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        assert len(exits) == len(structs) == 0
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    except AssertionError: 
							 | 
						
					
						
							
								
									
										
										
										
											2024-08-19 15:58:30 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        raise Exception(f"Failed to connect all Minecraft structures for player {player} ({self.player_name})")
							 | 
						
					
						
							
								
									
										
										
										
											2023-03-08 21:13:52 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    for exit in exits_spoiler:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        multiworld.get_entrance(exit, player).connect(multiworld.get_region(pairs[exit], player))
							 | 
						
					
						
							
								
									
										
										
										
											2024-08-19 15:58:30 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if self.options.shuffle_structures or self.options.plando_connections:
							 | 
						
					
						
							
								
									
										
										
										
											2023-03-08 21:13:52 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            multiworld.spoiler.set_entrance(exit, pairs[exit], 'entrance', player)
							 |