@@ -27,20 +27,19 @@ class Bot:
2727 _initialized_bot = False
2828 _has_match_settings = False
2929 _has_field_info = False
30+ _has_player_mapping = False
3031
31- _latest_packet : Optional [flat .GameTickPacket ] = None
32+ _latest_packet : Optional [flat .GamePacket ] = None
3233 _latest_prediction = flat .BallPrediction ()
3334
34- def __init__ (self ):
35- spawn_id = os .environ .get ("RLBOT_SPAWN_IDS" )
35+ def __init__ (self , default_agent_id : Optional [ str ] = None ):
36+ agent_id = os .environ .get ("RLBOT_AGENT_ID" ) or default_agent_id
3637
37- if spawn_id is None :
38- self .logger .warning ("RLBOT_SPAWN_IDS environment variable not set" )
39- else :
40- self .spawn_id = int (spawn_id )
41- self .logger .info ("Spawn ID: %s" , self .spawn_id )
38+ if agent_id is None :
39+ self .logger .critical ("RLBOT_AGENT_ID environment variable is not set" )
40+ exit (1 )
4241
43- self ._game_interface = SocketRelay (logger = self .logger )
42+ self ._game_interface = SocketRelay (agent_id , logger = self .logger )
4443 self ._game_interface .match_settings_handlers .append (self ._handle_match_settings )
4544 self ._game_interface .field_info_handlers .append (self ._handle_field_info )
4645 self ._game_interface .match_communication_handlers .append (
@@ -49,13 +48,23 @@ def __init__(self):
4948 self ._game_interface .ball_prediction_handlers .append (
5049 self ._handle_ball_prediction
5150 )
51+ self ._game_interface .controllable_team_info_handlers .append (
52+ self ._handle_player_mappings
53+ )
5254 self ._game_interface .packet_handlers .append (self ._handle_packet )
5355
5456 self .renderer = Renderer (self ._game_interface )
5557
56- def _initialize_agent (self ):
58+ def _initialize (self ):
59+ # search match settings for our name
60+ for player in self .match_settings .player_configurations :
61+ if player .spawn_id == self .spawn_id :
62+ self .name = player .name
63+ self .logger = get_logger (self .name )
64+ break
65+
5766 try :
58- self .initialize_agent ()
67+ self .initialize ()
5968 except Exception as e :
6069 self .logger .critical (
6170 "Bot %s failed to initialize due the following error: %s" , self .name , e
@@ -64,75 +73,53 @@ def _initialize_agent(self):
6473 exit ()
6574
6675 self ._initialized_bot = True
67- self ._game_interface .send_init_complete (flat . InitComplete ( self . spawn_id ) )
76+ self ._game_interface .send_init_complete ()
6877
6978 def _handle_match_settings (self , match_settings : flat .MatchSettings ):
7079 self .match_settings = match_settings
7180 self ._has_match_settings = True
7281
73- # search match settings for our spawn id
74- for player in self .match_settings .player_configurations :
75- if player .spawn_id == self .spawn_id :
76- self .team = player .team
77- self .name = player .name
78- self .logger = get_logger (self .name )
79- break
80-
81- if self .spawn_id == 0 :
82- match player .variety .item :
83- case flat .RLBot ():
84- self .team = player .team
85- self .name = player .name
86- self .logger = get_logger (self .name )
87- break
88-
89- if not self ._initialized_bot and self ._has_field_info :
90- self ._initialize_agent ()
82+ if (
83+ not self ._initialized_bot
84+ and self ._has_field_info
85+ and self ._has_player_mapping
86+ ):
87+ self ._initialize ()
9188
9289 def _handle_field_info (self , field_info : flat .FieldInfo ):
9390 self .field_info = field_info
9491 self ._has_field_info = True
9592
96- if not self ._initialized_bot and self ._has_match_settings :
97- self ._initialize_agent ()
93+ if (
94+ not self ._initialized_bot
95+ and self ._has_match_settings
96+ and self ._has_player_mapping
97+ ):
98+ self ._initialize ()
99+
100+ def _handle_player_mappings (self , player_mappings : flat .ControllableTeamInfo ):
101+ self .team = player_mappings .team
102+ controllable = player_mappings .controllables [0 ]
103+ self .spawn_id = controllable .spawn_id
104+ self .index = controllable .index
105+ self ._has_player_mapping = True
106+
107+ if (
108+ not self ._initialized_bot
109+ and self ._has_match_settings
110+ and self ._has_field_info
111+ ):
112+ self ._initialize ()
98113
99114 def _handle_ball_prediction (self , ball_prediction : flat .BallPrediction ):
100115 self ._latest_prediction = ball_prediction
101116
102- def _handle_packet (self , packet : flat .GameTickPacket ):
117+ def _handle_packet (self , packet : flat .GamePacket ):
103118 self ._latest_packet = packet
104119
105- def _packet_processor (self , packet : flat .GameTickPacket ):
106- if (
107- self .index == - 1
108- or len (packet .players ) <= self .index
109- or packet .players [self .index ].spawn_id != self .spawn_id
110- ):
111- # spawn id should only be 0 if RLBOT_SPAWN_IDS was not set
112- if self .spawn_id == 0 :
113- # in this case, if there's only one player, we can assume it's us
114- player_index = - 1
115- for i , player in enumerate (packet .players ):
116- # skip human players/psyonix bots
117- if not player .is_bot :
118- continue
119-
120- if player_index != - 1 :
121- self .logger .error (
122- "Multiple bots in the game, please set RLBOT_SPAWN_IDS"
123- )
124- return
125-
126- player_index = i
127- self .index = player_index
128-
129- for i , player in enumerate (packet .players ):
130- if player .spawn_id == self .spawn_id :
131- self .index = i
132- break
133-
134- if self .index == - 1 :
135- return
120+ def _packet_processor (self , packet : flat .GamePacket ):
121+ if len (packet .players ) <= self .index :
122+ return
136123
137124 self .ball_prediction = self ._latest_prediction
138125
@@ -162,9 +149,9 @@ def run(
162149
163150 # custom message handling logic
164151 # this reads all data in the socket until there's no more immediately available
165- # checks if there was a GameTickPacket in the data, and if so, processes it
152+ # checks if there was a GamePacket in the data, and if so, processes it
166153 # then sets the socket to non-blocking and waits for more data
167- # if there was no GameTickPacket , it sets to blocking and waits for more data
154+ # if there was no GamePacket , it sets to blocking and waits for more data
168155 while True :
169156 try :
170157 self ._game_interface .handle_incoming_messages (True )
@@ -271,23 +258,21 @@ def set_loadout(self, loadout: flat.PlayerLoadout, spawn_id: int):
271258 """
272259 Sets the loadout of a bot.
273260
274- For use as a loadout generator, call inside of `initialize_agent `.
275- Will be ignored if called outside of `initialize_agent ` when state setting is disabled.
261+ For use as a loadout generator, call inside of `initialize `.
262+ Will be ignored if called outside of `initialize ` when state setting is disabled.
276263 """
277264 self ._game_interface .send_set_loadout (flat .SetLoadout (spawn_id , loadout ))
278265
279- def initialize_agent (self ):
266+ def initialize (self ):
280267 """
281268 Called for all heaver initialization that needs to happen.
282- Field info and match settings are fully loaded at this point, and won't return garbage data.
283-
284- NOTE: `self.index` is not set at this point, and should not be used. `self.team` and `self.name` _are_ set with correct information.
269+ Field info, match settings, name, index, and team are fully loaded at this point, and won't return garbage data.
285270 """
286271
287272 def retire (self ):
288273 """Called after the game ends"""
289274
290- def get_output (self , packet : flat .GameTickPacket ) -> flat .ControllerState :
275+ def get_output (self , packet : flat .GamePacket ) -> flat .ControllerState :
291276 """
292277 Where all the logic of your bot gets its input and returns its output.
293278 """
0 commit comments