Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 3
Match Comm
fromrlbot.flatimportControllerState, GamePacketfromrlbot.managersimportBotclassQuickChatExampleAgent(Bot):
defget_output(self, packet: GamePacket) ->ControllerState:
# There won't be any content of the message for other bots,# but "I got it!" will be display for a human to see!self.send_match_comm(b"", "I got it!")
returnControllerState()
if__name__=="__main__":
QuickChatExampleAgent("rlbot_community/quickchat_example").run()This is just a simple example that spams "I got it!" to the screen for a human to read.
The method send_match_comm exists in the Bot class, so our QuickChatExampleAgent automatically inherits this class method when deriving from Bot.
The empty content (the b"") part of the messages means that other bots will likely ignore it.
A standard format for this field like TMCP should be used for this, but the field can contain any information at all. It does not have to be valid text.
fromrlbot.flatimportControllerState, GamePacketfromrlbot.managersimportBotclassQuickChatExampleAgent(Bot):
defget_output(self, packet: GamePacket) ->ControllerState:
returnControllerState()
defhandle_match_comm(
self,
index: int,
team: int,
content: bytes,
display: Optional[str],
team_only: bool,
):
ifdisplayisNone:
returnifteam==2:
print(f"Script @ index {index} (team {team}) said \"{display}\"")
else:
print(f"Bot @ index {index} (team {team}) said \"{display}\"")
if__name__=="__main__":
QuickChatExampleAgent("rlbot_community/quickchat_example").run()This example prints out every message that a human can see, and correctly identifies bots vs scripts.
Emits a match communication message to other bots and scripts.
For
Bot&Script:defsend_match_comm( self, content: bytes, display: Optional[str] =None, team_only: bool=False ): ...
For
Hivemind:defsend_match_comm( self, index: int, content: bytes, display: Optional[str] =None, team_only: bool=False, ): ...
index: This additional argument is the index of the bot that the message should be sent from.
Args:
content: The content of the message containing arbitrary data.display: The message to be displayed in the game in "quick chat", orNoneto display nothing.team_only: If True, only your team (blue/orange) will receive the message. For scripts, this means only other scripts.
Called when a match communication message is received.
defhandle_match_comm(
self,
index: int,
team: int,
content: bytes,
display: Optional[str],
team_only: bool,
): ...index: The sender's index.- If
teamis0or1: This is the index of the player in theGamePacket. - If
teamis2: This is the index of the script inself.match_config.script_configurations.
- If
team: The team that the sender is from.0for blue,1for orange, and2for scripts.content: The content of the message containing arbitrary data.display: The message that is ebing displayed in the game in "quick chat", orNoneif nothing was displayed.team_only: If True, only your team (blue/orange) received this message. For scripts, this means only other scripts.
The field content can be anything. It's just a bunch of raw bytes in a row.
How can you do something useful with this?
The following example sends & receives JSON, which is much easier to work with:
importjsonfromrlbot.flatimportControllerState, GamePacketfromrlbot.managersimportBotclassQuickChatExampleAgent(Bot):
player_names: list[str] = []
last_enemy_idx: int|None=Nonedefhandle_match_comm(
self,
index: int,
team: int,
content: bytes,
display: str|None,
team_only: bool,
):
ifteam!=self.teamornotcontent:
returnsender_name=self.player_names[index]
ifnotteam_only:
self.logger.warning(f"{sender_name} is leaking secrets to the other team!!")
returntry:
msg_str=content.decode("utf-8")
msg=json.loads(msg_str)
exceptUnicodeDecodeError:
returnexceptjson.JSONDecodeError:
returnif"target"inmsg:
self.logger.info(f"{sender_name} is targeting {msg['target']}")
defget_output(self, packet: GamePacket) ->ControllerState:
self.player_names= [p.nameforpinpacket.players]
first_enemy_idx=Nonefori, playerinenumerate(packet.players):
ifplayer.team!=self.teamandplayer.demolished_timeout==-1:
first_enemy_idx=ibreakiffirst_enemy_idxisnotNoneandfirst_enemy_idx!=self.last_enemy_idx:
player_name=self.player_names[first_enemy_idx]
msg= {"target": f"{player_name} - Player[{first_enemy_idx}]"}
msg_str=json.dumps(msg)
self.send_match_comm(msg_str.encode("utf-8"), "Here's Johnny!", team_only=True)
self.last_enemy_idx=first_enemy_idxreturnControllerState()
if__name__=="__main__":
QuickChatExampleAgent("rlbot_community/quickchat_example").run()In get_output, we:
Save the list of all the player names (into the variable
player_names) for later use and use inhandle_match_comm.Find the first player in
packetthat's on the enemy team and isn't yet demolished, saving the index infirst_enemy_idx.If
first_enemy_idxis different from the last tick and isn'tNone, send out a match comm:- This match comm will have a
contentsthat is serialized JSON containing our wanted information. - Will print out a message in the game saying "Here's Johnny!" for a human to see.
- A copy of this message will only be sent to the other bots on our team.
- This match comm will have a
Set
self.last_enemy_idxtofirst_enemy_idxfor us to use in the next tick.
In handle_match_comm, we:
- Ignore messages that aren't from our team or have no content.
- Check that the sent message was team only. If it's not, we call out our teammate and ignore the message! After all, we can't have our opponents knowing what we're going to do...
- Try to decode the message from bytes into JSON. If it's not valid JSON, we silently ignore the message. We can't understand it.
- Check if the variable
targetis inside our JSON. If it is, we log what our teammate is targeting! Realistically, we would store this information and use it to inform our game strategy.