Esempio n. 1
0
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
Esempio n. 2
0
def load_script_bundle(filename):
    try:
        bundle = get_script_config_bundle(filename)
        return [serialize_script_bundle(bundle)]
    except Exception as e:
        print(e)

    return []
Esempio n. 3
0
    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
Esempio n. 4
0
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}
Esempio n. 5
0
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}
Esempio n. 6
0
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
Esempio n. 7
0
    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
Esempio n. 8
0
    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
Esempio n. 9
0
    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(
        )