Skip to content

Commit 694d5fa

Browse files
committed
Experimental async packet processor
1 parent 2b4aeab commit 694d5fa

File tree

2 files changed

+71
-37
lines changed

2 files changed

+71
-37
lines changed

rlbot/managers/bot.py

Lines changed: 66 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import os
2+
from threading import Thread, Event
23
from traceback import print_exc
34
from typing import Optional
45

@@ -28,6 +29,12 @@ class Bot:
2829
_has_match_settings = False
2930
_has_field_info = False
3031

32+
_latest_packet = flat.GameTickPacket()
33+
_lastest_prediction = flat.BallPrediction()
34+
_packet_event = Event()
35+
_packet_thread = None
36+
_run_packet_thread = True
37+
3138
def __init__(self):
3239
spawn_id = os.environ.get("RLBOT_SPAWN_IDS")
3340

@@ -48,6 +55,9 @@ def __init__(self):
4855
)
4956
self._game_interface.packet_handlers.append(self._handle_packet)
5057

58+
self._packet_thread = Thread(target=self._packet_processor, daemon=True)
59+
self._packet_thread.start()
60+
5161
self.renderer = Renderer(self._game_interface)
5262

5363
def _initialize_agent(self):
@@ -86,49 +96,67 @@ def _handle_field_info(self, field_info: flat.FieldInfo):
8696
self._initialize_agent()
8797

8898
def _handle_ball_prediction(self, ball_prediction: flat.BallPrediction):
89-
self.ball_prediction = ball_prediction
99+
self._lastest_prediction = ball_prediction
90100

91101
def _handle_packet(self, packet: flat.GameTickPacket):
92-
if (
93-
self.index == -1
94-
or len(packet.players) <= self.index
95-
or packet.players[self.index].spawn_id != self.spawn_id
96-
):
97-
# spawn id should only be 0 if RLBOT_SPAWN_IDS was not set
98-
if self.spawn_id == 0:
99-
# in this case, if there's only one player, we can assume it's us
100-
player_index = -1
101-
for i, player in enumerate(packet.players):
102-
# skip human players/psyonix bots
103-
if not player.is_bot:
104-
continue
102+
self._latest_packet = packet
103+
self._packet_event.set()
105104

106-
if player_index != -1:
107-
self.logger.error(
108-
"Multiple bots in the game, please set RLBOT_SPAWN_IDS"
109-
)
110-
return
105+
def _packet_processor(self):
106+
while self._run_packet_thread:
107+
self._packet_event.wait()
111108

112-
player_index = i
113-
self.index = player_index
109+
# if the thread was unblocked,
110+
# but it we're not supposed to be running,
111+
# then exit
112+
if not self._run_packet_thread:
113+
return
114114

115-
for i, player in enumerate(packet.players):
116-
if player.spawn_id == self.spawn_id:
117-
self.index = i
118-
break
115+
self.ball_prediction = self._lastest_prediction
116+
packet: flat.GameTickPacket = self._latest_packet
117+
118+
self._packet_event.clear()
119+
120+
if (
121+
self.index == -1
122+
or len(packet.players) <= self.index
123+
or packet.players[self.index].spawn_id != self.spawn_id
124+
):
125+
# spawn id should only be 0 if RLBOT_SPAWN_IDS was not set
126+
if self.spawn_id == 0:
127+
# in this case, if there's only one player, we can assume it's us
128+
player_index = -1
129+
for i, player in enumerate(packet.players):
130+
# skip human players/psyonix bots
131+
if not player.is_bot:
132+
continue
133+
134+
if player_index != -1:
135+
self.logger.error(
136+
"Multiple bots in the game, please set RLBOT_SPAWN_IDS"
137+
)
138+
return
139+
140+
player_index = i
141+
self.index = player_index
119142

120-
if self.index == -1:
143+
for i, player in enumerate(packet.players):
144+
if player.spawn_id == self.spawn_id:
145+
self.index = i
146+
break
147+
148+
if self.index == -1:
149+
return
150+
151+
try:
152+
controller = self.get_output(packet)
153+
except Exception as e:
154+
self.logger.error("Bot %s returned an error to RLBot: %s", self.name, e)
155+
print_exc()
121156
return
122157

123-
try:
124-
controller = self.get_output(packet)
125-
except Exception as e:
126-
self.logger.error("Bot %s returned an error to RLBot: %s", self.name, e)
127-
print_exc()
128-
return
129-
130-
player_input = flat.PlayerInput(self.index, controller)
131-
self._game_interface.send_player_input(player_input)
158+
player_input = flat.PlayerInput(self.index, controller)
159+
self._game_interface.send_player_input(player_input)
132160

133161
def run(
134162
self,
@@ -144,6 +172,9 @@ def run(
144172
rlbot_server_port=rlbot_server_port,
145173
)
146174
finally:
175+
self._run_packet_thread = False
176+
self._packet_event.set()
177+
147178
self.retire()
148179
del self._game_interface
149180

rlbot/version.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
__version__ = "5.0.0-beta.1"
1+
__version__ = "5.0.0-beta.2"
22

33

44
RESET_SEQ = "\033[0m"
@@ -15,9 +15,12 @@ def _get_color(color: int) -> str:
1515
)
1616

1717
RELEASE_NOTES = {
18+
"5.0.0-beta.2": """
19+
Ensure bots don't fall behind the most recent GameTickPacket.
20+
""",
1821
"5.0.0-beta.1": """
1922
Initial iteration of the Python interface for RLBot.
20-
"""
23+
""",
2124
}
2225

2326
RELEASE_BANNER = f"""

0 commit comments

Comments
 (0)