diff options
author | Dominik Schmid <dominikschmid93@gmail.com> | 2019-04-18 00:57:31 +1000 |
---|---|---|
committer | Dominik Schmid <dominikschmid93@gmail.com> | 2019-04-18 00:57:31 +1000 |
commit | 5be54b53ae6738105bd7f1068c99bfbf20095b57 (patch) | |
tree | 82438c3fe927c56fec9ac1dde3f8dcb1fa39fb2f | |
parent | 6d066d2e72561b21c00c3a769b222c643690e889 (diff) |
First cut at getting an agent to connect to a server within setup_manager.pywebsocket-matchcomms
6 files changed, 56 insertions, 37 deletions
diff --git a/src/main/python/rlbot/agents/base_agent.py b/src/main/python/rlbot/agents/base_agent.py index abb9219e..844ff2f7 100644 --- a/src/main/python/rlbot/agents/base_agent.py +++ b/src/main/python/rlbot/agents/base_agent.py @@ -1,4 +1,8 @@ +from typing import Optional +from urllib.parse import ParseResult as URL + from rlbot.botmanager.helper_process_request import HelperProcessRequest +from rlbot.matchcomms.client import MatchcommsClient from rlbot.parsing.custom_config import ConfigObject from rlbot.utils.game_state_util import GameState from rlbot.utils.logging_utils import get_logger @@ -65,12 +69,11 @@ class BaseAgent: # passed in by the bot manager __quick_chat_func = None - - # passed in by the bot manager __field_info_func = None __game_state_func = None __get_rigid_body_tick_func = None renderer: RenderingManager = None + matchcomms_root: URL = None def __init__(self, name, team, index): self.name = name @@ -136,6 +139,16 @@ class BaseAgent: """Fetches a prediction of where the ball will go during the next few seconds.""" return self.__ball_prediction_struct_func() + _matchcomms_client: Optional[MatchcommsClient] = None + @property + def matchcomms_client(self) -> MatchcommsClient: + """ + Gets a client to send and recieve messages to other participants in the match (e.g. bots, trainer) + """ + if self._matchcomms_client is None: + self._matchcomms_client = MatchcommsClient(self.matchcomms_root) + return self._matchcomms_client # note: _matchcomms_client.close() is called by the bot_manager. + def load_config(self, config_object_header): """ Loads a config object this is called after the constructor but before anything else inside the bot. diff --git a/src/main/python/rlbot/botmanager/bot_manager.py b/src/main/python/rlbot/botmanager/bot_manager.py index 0ec979cd..6d984176 100644 --- a/src/main/python/rlbot/botmanager/bot_manager.py +++ b/src/main/python/rlbot/botmanager/bot_manager.py @@ -3,9 +3,11 @@ import time import traceback from datetime import datetime, timedelta import multiprocessing as mp +from urllib.parse import ParseResult as URL from rlbot.agents.base_agent import BaseAgent from rlbot.botmanager.agent_metadata import AgentMetadata +from rlbot.matchconfig.match_config import MatchConfig from rlbot.utils import rate_limiter from rlbot.utils.game_state_util import GameState from rlbot.utils.logging_utils import get_logger @@ -25,7 +27,8 @@ MAX_CARS = 10 class BotManager: def __init__(self, terminate_request_event, termination_complete_event, reload_request_event, bot_configuration, - name, team, index, agent_class_wrapper, agent_metadata_queue, quick_chat_queue_holder, match_config): + name, team, index, agent_class_wrapper, agent_metadata_queue, quick_chat_queue_holder, match_config: MatchConfig, + matchcomms_root: URL): """ :param terminate_request_event: an Event (multiprocessing) which will be set from the outside when the program is trying to terminate :param termination_complete_event: an Event (multiprocessing) which should be set from inside this class when termination has completed successfully @@ -39,6 +42,8 @@ class BotManager: :param agent_class_wrapper: The ExternalClassWrapper object that can be used to load and reload the bot :param agent_metadata_queue: a Queue (multiprocessing) which expects to receive AgentMetadata once available. :param quick_chat_queue_holder: A data structure which helps the bot send and receive quickchat + :param match_config: Describes the match that is being played. + :param matchcomms_root: The server to connect to if you want to communicate to other participants in the match. """ self.terminate_request_event = terminate_request_event self.termination_complete_event = termination_complete_event @@ -61,6 +66,7 @@ class BotManager: self.ball_prediction = None self.rigid_body_tick = None self.match_config = match_config + self.matchcomms_root = matchcomms_root def send_quick_chat_from_agent(self, team_only, quick_chat): """ @@ -101,6 +107,7 @@ class BotManager: agent._register_ball_prediction(self.get_ball_prediction) agent._register_ball_prediction_struct(self.get_ball_prediction_struct) agent._register_get_rigid_body_tick(self.get_rigid_body_tick) + agent.matchcomms_root = self.matchcomms_root if self.quick_chat_quit_event: self.quick_chat_quit_event.set() self.quick_chat_quit_event = mp.Event() @@ -222,6 +229,10 @@ class BotManager: self.game_interface.update_player_input(PlayerInput(), self.index) self.quick_chat_quit_event.set() # Shut down quick chat. + # Don't trust the agent to shut down its own client in retire(). + if agent._matchcomms_client is not None: + agent._matchcomms_client.close() + # If terminated, send callback self.termination_complete_event.set() diff --git a/src/main/python/rlbot/botmanager/bot_manager_flatbuffer.py b/src/main/python/rlbot/botmanager/bot_manager_flatbuffer.py index 54b9f179..16639f27 100644 --- a/src/main/python/rlbot/botmanager/bot_manager_flatbuffer.py +++ b/src/main/python/rlbot/botmanager/bot_manager_flatbuffer.py @@ -3,14 +3,11 @@ from rlbot.messages.flat import GameTickPacket class BotManagerFlatbuffer(BotManager): - def __init__(self, terminate_request_event, termination_complete_event, reload_request_event, bot_configuration, - name, team, index, agent_class_wrapper, agent_metadata_queue, quick_chat_queue_holder, match_config): + def __init__(self, *args, **kwargs): """ See documentation on BotManager. """ - super().__init__(terminate_request_event, termination_complete_event, reload_request_event, bot_configuration, - name, team, index, agent_class_wrapper, agent_metadata_queue, quick_chat_queue_holder, - match_config) + super().__init__(*args, **kwargs) self.game_tick_flat = None self.game_tick_flat_binary = None diff --git a/src/main/python/rlbot/botmanager/bot_manager_independent.py b/src/main/python/rlbot/botmanager/bot_manager_independent.py index 69dc9467..5ec75940 100644 --- a/src/main/python/rlbot/botmanager/bot_manager_independent.py +++ b/src/main/python/rlbot/botmanager/bot_manager_independent.py @@ -2,14 +2,11 @@ from rlbot.botmanager.bot_manager import BotManager class BotManagerIndependent(BotManager): - def __init__(self, terminate_request_event, termination_complete_event, reload_request_event, bot_configuration, - name, team, index, agent_class_wrapper, agent_metadata_queue, quick_chat_queue_holder, match_config): + def __init__(self, *args, **kwargs): """ See documentation on BotManager. """ - super().__init__(terminate_request_event, termination_complete_event, reload_request_event, bot_configuration, - name, team, index, agent_class_wrapper, agent_metadata_queue, quick_chat_queue_holder, - match_config) + super().__init__(*args, **kwargs) def run(self): # Get bot module diff --git a/src/main/python/rlbot/botmanager/bot_manager_struct.py b/src/main/python/rlbot/botmanager/bot_manager_struct.py index 4692004c..1debfc7d 100644 --- a/src/main/python/rlbot/botmanager/bot_manager_struct.py +++ b/src/main/python/rlbot/botmanager/bot_manager_struct.py @@ -8,14 +8,11 @@ from rlbot.utils.structures.rigid_body_struct import RigidBodyTick class BotManagerStruct(BotManager): - def __init__(self, terminate_request_event, termination_complete_event, reload_request_event, bot_configuration, - name, team, index, agent_class_wrapper, agent_metadata_queue, quick_chat_queue_holder, match_config): + def __init__(self, *args, **kwargs): """ See documentation on BotManager. """ - super().__init__(terminate_request_event, termination_complete_event, reload_request_event, bot_configuration, - name, team, index, agent_class_wrapper, agent_metadata_queue, quick_chat_queue_holder, - match_config) + super().__init__(*args, **kwargs) self.rigid_body_tick = None def prepare_for_run(self): diff --git a/src/main/python/rlbot/setup_manager.py b/src/main/python/rlbot/setup_manager.py index 35bf647e..3bdd600d 100644 --- a/src/main/python/rlbot/setup_manager.py +++ b/src/main/python/rlbot/setup_manager.py @@ -1,14 +1,15 @@ -from typing import List from contextlib import contextmanager from datetime import datetime, timedelta +from typing import List +from urllib.parse import ParseResult as URL import msvcrt import multiprocessing as mp import os +import psutil import queue import time import webbrowser -import psutil from rlbot import version from rlbot.base_extension import BaseExtension from rlbot.botmanager.bot_manager_flatbuffer import BotManagerFlatbuffer @@ -17,6 +18,7 @@ from rlbot.botmanager.bot_manager_struct import BotManagerStruct from rlbot.botmanager.helper_process_manager import HelperProcessManager from rlbot.matchconfig.conversions import parse_match_config from rlbot.matchconfig.match_config import MatchConfig +from rlbot.matchcomms.server import launch_matchcomms_server from rlbot.parsing.agent_config_parser import load_bot_appearance from rlbot.parsing.bot_config_bundle import get_bot_config_bundle from rlbot.parsing.custom_config import ConfigObject @@ -80,18 +82,6 @@ class SetupManager: extension = None bot_processes: List[mp.Process] = [] - _matchcomms_address: str = None - _matchcomms_process: mp.Process = None - @property - def foo(self): - if self._matchcomms_address is not None: - return self._matchcomms_address - - self._matchcomms_address = - return self._matchcomms_address - return self._foo - - def __init__(self): self.logger = get_logger(DEFAULT_LOGGER) @@ -104,6 +94,7 @@ class SetupManager: self.agent_metadata_map = {} self.ball_prediction_process = None self.match_config: MatchConfig = None + self.matchcomms_server: MatchcommsServerThread = None def connect_to_game(self): if self.has_started: @@ -202,6 +193,10 @@ class SetupManager: self.logger.debug("Launching bot processes") self.kill_bot_processes() + # Start matchcomms here as it's only required for the bots. + self.kill_matchcomms_server() + self.matchcomms_server = launch_matchcomms_server() + # Launch processes for i in range(self.num_participants): if self.start_match_configuration.player_configuration[i].rlbot_controlled: @@ -214,7 +209,7 @@ class SetupManager: args=(self.quit_event, quit_callback, reload_request, self.parameters[i], str(self.start_match_configuration.player_configuration[i].name), self.teams[i], i, self.python_files[i], self.agent_metadata_queue, - queue_holder, self.match_config)) + queue_holder, self.match_config, self.matchcomms_server.root_url)) process.start() self.bot_processes.append(process) @@ -301,6 +296,8 @@ class SetupManager: if kill_all_pids: self.kill_agent_process_ids() + self.kill_matchcomms_server() + # The quit event can only be set once. Let's reset to our initial state self.quit_event = mp.Event() self.helper_process_manager = HelperProcessManager(self.quit_event) @@ -318,19 +315,22 @@ class SetupManager: @staticmethod def run_agent(terminate_event, callback_event, reload_request, config_file, name, team, index, python_file, - agent_telemetry_queue, queue_holder, match_config: MatchConfig): + agent_telemetry_queue, queue_holder, match_config: MatchConfig, matchcomms_root: URL): agent_class_wrapper = import_agent(python_file) if hasattr(agent_class_wrapper.get_loaded_class(), "run_independently"): bm = BotManagerIndependent(terminate_event, callback_event, reload_request, config_file, name, team, index, - agent_class_wrapper, agent_telemetry_queue, queue_holder, match_config) + agent_class_wrapper, agent_telemetry_queue, queue_holder, match_config, + matchcomms_root) elif hasattr(agent_class_wrapper.get_loaded_class(), "get_output_flatbuffer"): bm = BotManagerFlatbuffer(terminate_event, callback_event, reload_request, config_file, name, team, index, - agent_class_wrapper, agent_telemetry_queue, queue_holder, match_config) + agent_class_wrapper, agent_telemetry_queue, queue_holder, match_config, + matchcomms_root) else: bm = BotManagerStruct(terminate_event, callback_event, reload_request, config_file, name, team, index, - agent_class_wrapper, agent_telemetry_queue, queue_holder, match_config) + agent_class_wrapper, agent_telemetry_queue, queue_holder, match_config, + matchcomms_root) bm.run() def kill_bot_processes(self): @@ -359,6 +359,10 @@ class SetupManager: except psutil.NoSuchProcess: self.logger.info("Can't fetch parent process, already dead.") + def kill_matchcomms_server(self): + if self.matchcomms_server: + self.matchcomms_server.close() + self.matchcomms_server = None def load_bot_parameters(config_bundle) -> ConfigObject: """ |