def make_match_config(challenge: dict, upgrades: dict, player_configs: List[PlayerConfig], script_configs: List[ScriptConfig]): """Setup the match, following the challenge rules and user's upgrades """ match_config = MatchConfig() match_config.mutators = MutatorConfig() match_config.game_mode = game_mode_types[0] # Soccar match_config.game_map = challenge.get("map") match_config.enable_state_setting = True for script_config in script_configs: script_config_bundle = get_script_config_bundle( script_config.config_path) script_class_wrapper = import_class_with_base( script_config_bundle.script_file, BaseStoryScript) script_class = script_class_wrapper.get_loaded_class() if "edit_match_config" in dir(script_class): enabled_upgrades = list( filter(lambda upgrade: upgrades[upgrade], upgrades.keys())) script_class.edit_match_config(match_config, challenge, enabled_upgrades) if DEBUG_MODE_SHORT_GAMES: match_config.mutators.max_score = "3 Goals" match_config.player_configs = player_configs match_config.script_configs = script_configs return match_config
def load_script_bundle(filename): try: bundle = get_script_config_bundle(filename) return [serialize_script_bundle(bundle)] except Exception as e: print(e) return []
def load_match_config(self, match_config: MatchConfig, bot_config_overrides={}): """ Loads the match config into internal data structures, which prepares us to later launch bot processes and start the match. This is an alternative to the load_config method; they accomplish the same thing. """ self.num_participants = match_config.num_players self.names = [bot.name for bot in match_config.player_configs] self.teams = [bot.team for bot in match_config.player_configs] for player in match_config.player_configs: if player.bot and not player.rlbot_controlled and not player.loadout_config: set_random_psyonix_bot_preset(player) bundles = [ bot_config_overrides[index] if index in bot_config_overrides else get_bot_config_bundle(bot.config_path) if bot.config_path else None for index, bot in enumerate(match_config.player_configs) ] self.python_files = [ bundle.python_file if bundle else None for bundle in bundles ] self.bot_bundles = [] for index, bot in enumerate(match_config.player_configs): self.bot_bundles.append(bundles[index]) if bot.loadout_config is None and bundles[index]: bot.loadout_config = bundles[index].generate_loadout_config( index, bot.team) if match_config.extension_config is not None and match_config.extension_config.python_file_path is not None: self.load_extension(match_config.extension_config.python_file_path) for bundle in self.bot_bundles: if bundle is not None and bundle.use_virtual_environment: builder = EnvBuilderWithRequirements(bundle=bundle) builder.create(Path(bundle.config_directory) / 'venv') for script_config in match_config.script_configs: script_config_bundle = get_script_config_bundle( script_config.config_path) if script_config_bundle.use_virtual_environment: builder = EnvBuilderWithRequirements( bundle=script_config_bundle) builder.create( Path(script_config_bundle.config_directory) / 'venv') self.match_config = match_config self.start_match_configuration = match_config.create_match_settings() self.game_interface.start_match_flatbuffer = match_config.create_flatbuffer( ) self.game_interface.start_match_configuration = self.start_match_configuration
def install_requirements(config_path): try: bundle = get_bot_config_bundle(config_path) except Exception: bundle = get_script_config_bundle(config_path) if bundle.requirements_file: exit_code = install_requirements_file(bundle.requirements_file) return {'exitCode': exit_code, 'package': bundle.requirements_file} else: return {'exitCode': 1, 'package': None}
def install_requirements(config_path): try: bundle = get_bot_config_bundle(config_path) except Exception: bundle = get_script_config_bundle(config_path) if bundle.requirements_file: exit_code = install_requirements_file(bundle.requirements_file) installed_packages = [ r.line for r in bundle.get_missing_python_packages() + bundle.get_python_packages_needing_upgrade() ] return {'exitCode': exit_code, 'packages': installed_packages} else: return {'exitCode': 1, 'packages': None}
def scan_directory_for_script_configs(root_dir) -> Set[ScriptConfigBundle]: """ Recursively scans a directory for all valid script configs. :param root_dir: Directory to scan. :return: The set of script configs that were found. """ configs = set() for filename in glob.iglob(os.path.join(root_dir, '**/*.cfg'), recursive=True): try: bundle = get_script_config_bundle(filename) configs.add(bundle) except (NoSectionError, MissingSectionHeaderError, NoOptionError, AttributeError, ParsingError, FileNotFoundError): pass return configs
def launch_bot_process_helper(self, early_starters_only=False, match_config: MatchConfig = None): # Start matchcomms here as it's only required for the bots. self.kill_matchcomms_server() self.matchcomms_server = launch_matchcomms_server() self.bot_processes = { ind: proc for ind, proc in self.bot_processes.items() if proc.is_alive() } num_started = 0 # Launch processes # TODO: this might be the right moment to fix the player indices based on a game tick packet. if not early_starters_only: packet = get_one_packet() # TODO: root through the packet and find discrepancies in the player index mapping. for i in range( min(self.num_participants, len(match_config.player_configs))): player_config = match_config.player_configs[i] if not player_config.has_bot_script(): continue if early_starters_only and not self.bot_bundles[ i].supports_early_start: continue spawn_id = player_config.spawn_id if early_starters_only: # Danger: we have low confidence in this since we're not leveraging the spawn id. participant_index = i else: participant_index = None self.logger.info( f'Player in slot {i} was sent with spawn id {spawn_id}, will search in the packet.' ) for n in range(0, packet.PlayersLength()): packet_spawn_id = packet.Players(n).SpawnId() if spawn_id == packet_spawn_id: self.logger.info( f'Looks good, considering participant index to be {n}' ) participant_index = n if participant_index is None: for prox_index, proc_info in self.bot_processes.items(): if spawn_id == proc_info.player_config.spawn_id: participant_index = prox_index if participant_index is None: raise Exception( f"Unable to determine the bot index for spawn id {spawn_id}" ) if participant_index not in self.bot_processes: bundle = get_bot_config_bundle(player_config.config_path) name = str(self.match_config.player_configs[i].deduped_name) if bundle.supports_standalone: executable = sys.executable if bundle.use_virtual_environment: executable = str( Path(bundle.config_directory) / 'venv' / 'Scripts' / 'python.exe') process = subprocess.Popen( [ executable, bundle.python_file, '--config-file', str(player_config.config_path), '--name', name, '--team', str(self.teams[i]), '--player-index', str(participant_index), '--spawn-id', str(spawn_id), '--matchcomms-url', self.matchcomms_server.root_url.geturl() ], cwd=Path(bundle.config_directory).parent) self.bot_processes[participant_index] = BotProcessInfo( process=None, subprocess=process, player_config=player_config) # Insert immediately into the agent metadata map because the standalone process has no way to communicate it back out self.agent_metadata_map[participant_index] = AgentMetadata( participant_index, name, self.teams[i], {process.pid}) else: reload_request = mp.Event() quit_callback = mp.Event() self.bot_reload_requests.append(reload_request) self.bot_quit_callbacks.append(quit_callback) process = mp.Process( target=SetupManager.run_agent, args=(self.quit_event, quit_callback, reload_request, self.bot_bundles[i], name, self.teams[i], participant_index, self.python_files[i], self.agent_metadata_queue, match_config, self.matchcomms_server.root_url, spawn_id)) process.start() self.bot_processes[participant_index] = BotProcessInfo( process=process, subprocess=None, player_config=player_config) num_started += 1 self.logger.info(f"Successfully started {num_started} bot processes") process_configuration.configure_processes(self.agent_metadata_map, self.logger) scripts_started = 0 for script_config in match_config.script_configs: script_config_bundle = get_script_config_bundle( script_config.config_path) if early_starters_only and not script_config_bundle.supports_early_start: continue executable = sys.executable if script_config_bundle.use_virtual_environment: executable = str( Path(script_config_bundle.config_directory) / 'venv' / 'Scripts' / 'python.exe') process = subprocess.Popen( [executable, script_config_bundle.script_file], cwd=Path(script_config_bundle.config_directory).parent) self.logger.info( f"Started script with pid {process.pid} using {process.args}") self.script_processes[process.pid] = process scripts_started += 1 self.logger.debug(f"Successfully started {scripts_started} scripts") return num_started
def launch_bot_process_helper(self, early_starters_only=False): # Start matchcomms here as it's only required for the bots. self.kill_matchcomms_server() self.matchcomms_server = launch_matchcomms_server() num_started = 0 # Launch processes # TODO: this might be the right moment to fix the player indices based on a game tick packet. packet = game_data_struct.GameTickPacket() self.game_interface.update_live_data_packet(packet) # TODO: root through the packet and find discrepancies in the player index mapping. for i in range(self.num_participants): if not self.start_match_configuration.player_configuration[i].rlbot_controlled: continue if early_starters_only and not self.bot_bundles[i].supports_early_start: continue bot_manager_spawn_id = None if early_starters_only: # Don't use a spawn id stuff for the early start system. The bots will be starting up before # the car spawns, and we don't want the bot manager to panic. participant_index = i else: participant_index = None spawn_id = self.game_interface.start_match_configuration.player_configuration[i].spawn_id self.logger.info(f'Player in slot {i} was sent with spawn id {spawn_id}, will search in the packet.') for n in range(0, packet.num_cars): packet_spawn_id = packet.game_cars[n].spawn_id if spawn_id == packet_spawn_id: self.logger.info(f'Looks good, considering participant index to be {n}') participant_index = n bot_manager_spawn_id = spawn_id if participant_index is None: raise Exception("Unable to determine the bot index!") if participant_index not in self.bot_processes: reload_request = mp.Event() quit_callback = mp.Event() self.bot_reload_requests.append(reload_request) self.bot_quit_callbacks.append(quit_callback) process = mp.Process(target=SetupManager.run_agent, args=(self.quit_event, quit_callback, reload_request, self.bot_bundles[i], str(self.start_match_configuration.player_configuration[i].name), self.teams[i], participant_index, self.python_files[i], self.agent_metadata_queue, self.match_config, self.matchcomms_server.root_url, bot_manager_spawn_id)) process.start() self.bot_processes[i] = process num_started += 1 self.logger.debug(f"Successfully started {num_started} bot processes") scripts_started = 0 for script_config in self.match_config.script_configs: script_config_bundle = get_script_config_bundle(script_config.config_path) if early_starters_only and not script_config_bundle.supports_early_start: continue process = subprocess.Popen([sys.executable, script_config_bundle.script_file], shell=True, cwd=Path(script_config_bundle.config_directory).parent) self.logger.info(f"Started script with pid {process.pid} using {process.args}") self.script_processes[process.pid] = process scripts_started += 1 self.logger.debug(f"Successfully started {scripts_started} scripts") return num_started
def load_match_config(self, match_config: MatchConfig, bot_config_overrides={}): """ Loads the match config into internal data structures, which prepares us to later launch bot processes and start the match. This is an alternative to the load_config method; they accomplish the same thing. """ self.num_participants = match_config.num_players self.names = [bot.name for bot in match_config.player_configs] self.teams = [bot.team for bot in match_config.player_configs] for player in match_config.player_configs: if player.bot and not player.rlbot_controlled and not player.loadout_config: set_random_psyonix_bot_preset(player) bundles = [ bot_config_overrides[index] if index in bot_config_overrides else get_bot_config_bundle(bot.config_path) if bot.config_path else None for index, bot in enumerate(match_config.player_configs) ] self.python_files = [ bundle.python_file if bundle else None for bundle in bundles ] self.bot_bundles = [] for index, bot in enumerate(match_config.player_configs): self.bot_bundles.append(bundles[index]) if bot.loadout_config is None and bundles[index]: bot.loadout_config = bundles[index].generate_loadout_config( index, bot.team) if match_config.extension_config is not None and match_config.extension_config.python_file_path is not None: self.load_extension(match_config.extension_config.python_file_path) try: urlopen("http://google.com") checked_environment_requirements = set() online = True except URLError: print("The user is offline, skipping upgrade the bot requirements") online = False for bundle in self.bot_bundles: if bundle is not None and bundle.use_virtual_environment: do_post_setup = online if do_post_setup: if bundle.requirements_file in checked_environment_requirements: do_post_setup = False else: checked_environment_requirements.add( bundle.requirements_file) builder = EnvBuilderWithRequirements( bundle=bundle, do_post_setup=do_post_setup) builder.create(Path(bundle.config_directory) / 'venv') for script_config in match_config.script_configs: script_config_bundle = get_script_config_bundle( script_config.config_path) if script_config_bundle.use_virtual_environment: do_post_setup = online if do_post_setup: if bundle.requirements_file in checked_environment_requirements: do_post_setup = False else: checked_environment_requirements.add( bundle.requirements_file) builder = EnvBuilderWithRequirements( bundle=script_config_bundle, do_post_setup=do_post_setup) builder.create( Path(script_config_bundle.config_directory) / 'venv') self.match_config = match_config self.game_interface.match_config = match_config self.game_interface.start_match_flatbuffer = match_config.create_flatbuffer( )