def load_all_bots(ld: LeagueDir) -> Mapping[BotID, BotConfigBundle]: bots = { fmt_bot_name(bot_config.name): bot_config for bot_config in scan_directory_for_bot_configs(ld.bots) } # Psyonix bots psyonix_allstar = get_bot_config_bundle(PackageFiles.psyonix_allstar) psyonix_pro = get_bot_config_bundle(PackageFiles.psyonix_pro) psyonix_rookie = get_bot_config_bundle(PackageFiles.psyonix_rookie) psyonix_allstar_name = fmt_bot_name(psyonix_allstar.name) psyonix_pro_name = fmt_bot_name(psyonix_pro.name) psyonix_rookie_name = fmt_bot_name(psyonix_rookie.name) bots[psyonix_allstar_name] = psyonix_allstar bots[psyonix_pro_name] = psyonix_pro bots[psyonix_rookie_name] = psyonix_rookie # Psyonix bots have skill values psyonix_bot_skill[psyonix_allstar_name] = 1.0 psyonix_bot_skill[psyonix_pro_name] = 0.5 psyonix_bot_skill[psyonix_rookie_name] = 0.0 return bots
def set_logo(blue_config, orange_config): #reused for logo later default_logo = os.path.join(files_path, 'logo.png') blue_config_bun = get_bot_config_bundle(blue_config) orange_config_bun = get_bot_config_bundle(orange_config) blue_logo = blue_config_bun.get_logo_file() if blue_logo is None: blue_logo = default_logo orange_logo = orange_config_bun.get_logo_file() if orange_logo is None: orange_logo = default_logo default_logo_scale = 0.25 default_logo_size = [400*default_logo_scale, 300*default_logo_scale] blue_logo_size = list(Image.open(blue_logo).size) blue_scale = default_logo_size[0]/blue_logo_size[0] orange_logo_size = list(Image.open(orange_logo).size) orange_scale = default_logo_size[0]/orange_logo_size[0] scenes = obs.obs_frontend_get_scenes() if scenes is not None: for scene in scenes: if obs.obs_source_get_name(scene) == 'RLBot - AutoLeague': scene = obs.obs_scene_from_source(scene) items = obs.obs_scene_enum_items(scene) for item in items: if item is not None: source_t = obs.obs_sceneitem_get_source(item) if obs.obs_source_get_name(source_t) == "Logo-0": source = source_t settings = obs.obs_data_create() obs.obs_data_set_string(settings, "file", blue_logo) obs.obs_source_update(source, settings) obs.obs_data_release(settings) vec = obs.vec2() obs.vec2_set(vec, blue_scale, blue_scale) obs.obs_sceneitem_set_scale(item, vec) if obs.obs_source_get_name(source_t) == "Logo-1": source = source_t settings = obs.obs_data_create() obs.obs_data_set_string(settings, "file", orange_logo) obs.obs_source_update(source, settings) obs.obs_data_release(settings) vec = obs.vec2() obs.vec2_set(vec, orange_scale, orange_scale) obs.obs_sceneitem_set_scale(item, vec) obs.source_list_release(scenes) obs.sceneitem_list_release(items)
def load_psyonix_bots(): """ Loads Psyonix bot configs and records some data about skill level. """ psyonix_allstar = get_bot_config_bundle(PackageFiles.psyonix_allstar) psyonix_pro = get_bot_config_bundle(PackageFiles.psyonix_pro) psyonix_rookie = get_bot_config_bundle(PackageFiles.psyonix_rookie) # Map Psyonix names to their skill value psyonix_bots_skill[psyonix_allstar.name] = 1.0 psyonix_bots_skill[psyonix_pro.name] = 0.5 psyonix_bots_skill[psyonix_rookie.name] = 0.0 return psyonix_allstar, psyonix_pro, psyonix_rookie
def set_dev_name(blue_config, orange_config): #reused for logo later default_dev_name = '' blue_config_bun = get_bot_config_bundle(blue_config) orange_config_bun = get_bot_config_bundle(orange_config) blue_dev_name = blue_config_bun.base_agent_config.get('Details', 'developer') if blue_dev_name is None: blue_dev_name = default_dev_name orange_dev_name = orange_config_bun.base_agent_config.get('Details', 'developer') if orange_dev_name is None: orange_dev_name = default_dev_name set_names('Blue-Dev-Name', blue_dev_name) set_names('Orange-Dev-Name', orange_dev_name)
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: 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) self.match_config = match_config self.start_match_configuration = match_config.create_match_settings() self.game_interface.start_match_configuration = self.start_match_configuration
def __init__(self, name, file_path=None): self.looks_path = None self.logger = get_logger('agent_preset') if file_path is not None and os.path.isfile(file_path): config_bundle = get_bot_config_bundle(file_path) self.looks_path = config_bundle.get_absolute_path( BOT_CONFIG_MODULE_HEADER, LOOKS_CONFIG_KEY) python_file_path = config_bundle.get_absolute_path( BOT_CONFIG_MODULE_HEADER, PYTHON_FILE_KEY) else: python_file_path = inspect.getfile(BaseAgent) try: self.agent_class = import_agent( python_file_path).get_loaded_class() super().__init__( self.agent_class.base_create_agent_configurations(), file_path, name) except (ValueError, ModuleNotFoundError, FileNotFoundError) as e: raise ValueError(f"Problem when processing {file_path}: {str(e)}") except ImportError as e: self.logger.debug( f"Will not use custom config for {file_path} because we failed to load: {str(e)}" ) super().__init__(BaseAgent.base_create_agent_configurations(), file_path, name) # Make sure the path to the python file actually gets set to that path, even if there was no config at file_path self.config.set_value(BOT_CONFIG_MODULE_HEADER, PYTHON_FILE_KEY, python_file_path)
def load_all_bots(working_dir: WorkingDir) -> Mapping[str, BotConfigBundle]: bots = dict(working_dir.get_bots()) # Psyonix bots psyonix_allstar = get_bot_config_bundle(PackageFiles.psyonix_allstar) psyonix_pro = get_bot_config_bundle(PackageFiles.psyonix_pro) psyonix_rookie = get_bot_config_bundle(PackageFiles.psyonix_rookie) bots[psyonix_allstar.name] = psyonix_allstar bots[psyonix_pro.name] = psyonix_pro bots[psyonix_rookie.name] = psyonix_rookie # Skill values for later. This way the user can rename the Psyonix bots by changing the config files, but we still # have their correct skill psyonix_bots[psyonix_allstar.name] = 1.0 psyonix_bots[psyonix_pro.name] = 0.5 psyonix_bots[psyonix_rookie.name] = 0.0 return bots
def load_bot_bundle(filename): try: bundle = get_bot_config_bundle(filename) return [serialize_bundle(bundle)] except Exception as e: print(e) return []
def run_bot(agent_class: Type[StandaloneBot]): config = StandaloneBotConfig(sys.argv) python_file = inspect.getfile(agent_class) config_obj = agent_class.base_create_agent_configurations() bundle = None if config.config_file is not None: # If the config file was not passed, then the bot will miss out on any custom configuration, # tick rate preference, etc. bundle = get_bot_config_bundle( Path(python_file).parent / config.config_file) config_obj.parse_file(bundle.config_obj, config_directory=bundle.config_directory) spawn_id = config.spawn_id player_index = config.player_index team = config.team name = config.name if config.is_missing_args: # This process must not have been created by the RLBot framework, so this is probably # a developer doing some testing who did not pass all the params. Take it upon ourselves # to fire up the game if necessary. print( f'############################################################################################' ) print( f'Args are missing, so we will assume this is a dev workflow and insert the bot into the game!' ) print( f'############################################################################################' ) test_spawner = TestSpawner(Path(python_file), config, bundle) test_spawner.spawn_bot() spawn_id = test_spawner.spawn_id player_index = test_spawner.player_index team = test_spawner.team name = test_spawner.name agent_class_wrapper = ExternalClassWrapper(python_file, StandaloneBot) # Pass in dummy objects for mp.Event, mp.Queue. We will not support that # functionality for standalone bots; it's generally unused anyway. bot_manager = BotManagerStruct(terminate_request_event=mp.Event(), termination_complete_event=mp.Event(), reload_request_event=mp.Event(), bot_configuration=config_obj, name=name, team=team, index=player_index, agent_class_wrapper=agent_class_wrapper, agent_metadata_queue=mp.Queue(), match_config=None, matchcomms_root=config.matchcomms_url, spawn_id=spawn_id) bot_manager.run()
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.game_interface.match_config = match_config self.game_interface.start_match_flatbuffer = match_config.create_flatbuffer( )
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 bot_config(player_config_path: Path, team: Team) -> 'PlayerConfig': """ A function to cover the common case of creating a config for a bot. """ bot_config = PlayerConfig() bot_config.bot = True bot_config.rlbot_controlled = True bot_config.team = team.value bot_config.config_path = str(player_config_path.absolute()) # TODO: Refactor to use Path's config_bundle = get_bot_config_bundle(bot_config.config_path) bot_config.name = config_bundle.name bot_config.loadout_config = load_bot_appearance(config_bundle.get_looks_config(), bot_config.team) return bot_config
def rlbot_to_player_config(player: dict, team: Team): bot_path = collapse_path(player["path"]) player_config = PlayerConfig() player_config.bot = True player_config.rlbot_controlled = True player_config.name = player["name"] player_config.team = team.value player_config.config_path = bot_path config = get_bot_config_bundle(bot_path) loadout = load_bot_appearance(config.get_looks_config(), team.value) player_config.loadout_config = loadout return player_config
def load_bundle(filename): try: bundle = get_bot_config_bundle(filename) return [{ 'name': bundle.name, 'type': 'rlbot', 'image': 'imgs/rlbot.png', 'path': bundle.config_path, 'info': read_info(bundle) }] except Exception as e: print(e) return []
def run_bot(agent_class: Type[ExecutableWithSocketStandaloneBot]): config = StandaloneBotConfig(sys.argv) bundle = get_bot_config_bundle(config.config_file) config_obj = agent_class.base_create_agent_configurations() config_obj.parse_file(bundle.config_obj, config_directory=bundle.config_directory) agent = agent_class(config.name, config.team, config.player_index) agent.spawn_id = config.spawn_id agent.load_config(config_obj.get_header(BOT_CONFIG_AGENT_HEADER)) if not agent.send_add_command(): agent.launch_executable() agent.run_independently(multiprocessing.Event()) agent.retire()
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 pick_bot_config(): filename = pick_bot_location(False) try: bundle = get_bot_config_bundle(filename) return [{ 'name': bundle.name, 'type': 'rlbot', 'image': 'imgs/rlbot.png', 'path': bundle.config_path, 'info': read_info(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] self.configs = [bot.config_path for bot in match_config.player_configs] 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]: looks_config = bundles[index].get_looks_config() bot.loadout_config = load_bot_appearance(looks_config, bot.team) for path in match_config.botless_agents: try: spec = impu.spec_from_file_location(path) m = impu.module_from_spec(spec) spec.loader.exec_module(m) if m.hasattr("agent"): self.botless_agents.append(m.agent()) else: self.logg.warning(f"No agent class found in {path}") except: self.logger.warning(f"Failed to import botless agent at {path}.") 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) self.match_config = match_config self.start_match_configuration = match_config.create_match_settings() self.game_interface.start_match_configuration = self.start_match_configuration
def scan_directory_for_bot_configs(root_dir) -> Set[BotConfigBundle]: """ Recursively scans a directory for all valid bot configs. :param root_dir: Directory to scan. :return: The set of bot configs that were found. """ configs = set() for filename in glob.iglob(os.path.join(root_dir, '**/*.cfg'), recursive=True): try: bundle = get_bot_config_bundle(filename) configs.add(bundle) except (NoSectionError, MissingSectionHeaderError, NoOptionError, AttributeError, ParsingError, FileNotFoundError) as ex: pass return configs
def rlbot_to_player_config(player: dict, team: Team): bot_path = player["path"] if isinstance(bot_path, list): bot_path = path.join(*bot_path) if "$RLBOTPACKROOT" in bot_path: for bot_folder in rlbot_gui.bot_folder_settings["folders"].keys(): adjusted_folder = path.join(bot_folder, "RLBotPack-master") subbed_path = bot_path.replace("$RLBOTPACKROOT", adjusted_folder) if path.exists(subbed_path): print("it exists!") bot_path = subbed_path break player_config = PlayerConfig() player_config.bot = True player_config.rlbot_controlled = True player_config.name = player["name"] player_config.team = team.value player_config.config_path = bot_path config = get_bot_config_bundle(bot_path) loadout = load_bot_appearance(config.get_looks_config(), team.value) player_config.loadout_config = loadout return player_config
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( )
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 make_test_match(bot_id: BotID) -> MatchDetails: allstar_config = get_bot_config_bundle(PackageFiles.psyonix_allstar) allstar_id = fmt_bot_name(allstar_config.name) team = [bot_id, allstar_id, allstar_id] return MatchDetails("", f"test_{bot_id}", team, team, "ChampionsField")