Skip to content

Commit 76297c4

Browse files
authored
Merge pull request #2 from VirxEC/skip
Async packet handling
2 parents 2b4aeab + 6b9d35b commit 76297c4

File tree

4 files changed

+76
-16
lines changed

4 files changed

+76
-16
lines changed

rlbot/managers/bot.py

Lines changed: 47 additions & 10 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,9 +96,13 @@ 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):
102+
self._latest_packet = packet
103+
self._packet_event.set()
104+
105+
def _packet_preprocess(self, packet: flat.GameTickPacket) -> bool:
92106
if (
93107
self.index == -1
94108
or len(packet.players) <= self.index
@@ -107,7 +121,7 @@ def _handle_packet(self, packet: flat.GameTickPacket):
107121
self.logger.error(
108122
"Multiple bots in the game, please set RLBOT_SPAWN_IDS"
109123
)
110-
return
124+
return False
111125

112126
player_index = i
113127
self.index = player_index
@@ -118,17 +132,37 @@ def _handle_packet(self, packet: flat.GameTickPacket):
118132
break
119133

120134
if self.index == -1:
135+
return False
136+
137+
return True
138+
139+
def _packet_processor(self):
140+
while self._run_packet_thread:
141+
self._packet_event.wait()
142+
143+
# if the thread was unblocked,
144+
# but it we're not supposed to be running,
145+
# then exit
146+
if not self._run_packet_thread:
121147
return
122148

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
149+
self.ball_prediction = self._lastest_prediction
150+
packet: flat.GameTickPacket = self._latest_packet
151+
152+
self._packet_event.clear()
153+
154+
if not self._packet_preprocess(packet):
155+
continue
129156

130-
player_input = flat.PlayerInput(self.index, controller)
131-
self._game_interface.send_player_input(player_input)
157+
try:
158+
controller = self.get_output(packet)
159+
except Exception as e:
160+
self.logger.error("Bot %s returned an error to RLBot: %s", self.name, e)
161+
print_exc()
162+
continue
163+
164+
player_input = flat.PlayerInput(self.index, controller)
165+
self._game_interface.send_player_input(player_input)
132166

133167
def run(
134168
self,
@@ -144,6 +178,9 @@ def run(
144178
rlbot_server_port=rlbot_server_port,
145179
)
146180
finally:
181+
self._run_packet_thread = False
182+
self._packet_event.set()
183+
147184
self.retire()
148185
del self._game_interface
149186

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"""

tests/atba/atba.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ def get_output(self, packet: flat.GameTickPacket) -> flat.ControllerState:
9797
return self.controller
9898

9999
if self.state_setting:
100-
self.test_state_setting(packet.balls[0].physics.velocity)
100+
self.test_state_setting(packet)
101101

102102
if self.match_comms:
103103
# Limit packet spam
@@ -119,15 +119,27 @@ def get_output(self, packet: flat.GameTickPacket) -> flat.ControllerState:
119119

120120
return self.controller
121121

122-
def test_state_setting(self, ball_velocity: flat.Vector3):
122+
def test_state_setting(self, packet: flat.GameTickPacket):
123123
game_state = flat.DesiredGameState(
124124
[
125125
flat.DesiredBallState(
126126
flat.DesiredPhysics(
127-
velocity=flat.Vector3Partial(z=ball_velocity.z + 10)
127+
velocity=flat.Vector3Partial(
128+
z=packet.balls[0].physics.velocity.z + 10
129+
)
128130
)
129131
)
130-
]
132+
],
133+
[
134+
flat.DesiredCarState(
135+
flat.DesiredPhysics(
136+
velocity=flat.Vector3Partial(
137+
z=packet.players[i].physics.velocity.z + 1
138+
)
139+
)
140+
)
141+
for i in range(len(packet.players))
142+
],
131143
)
132144
self.set_game_state(game_state)
133145

tests/necto/bot.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,14 @@ class Necto(Bot):
5454
def initialize_agent(self):
5555
# Initialize the rlgym GameState object now that the game is active and the info is available
5656
self.obs_builder = NectoObsBuilder(self.field_info)
57+
58+
if len(self.field_info.boost_pads) != 34:
59+
self.logger.warning(
60+
"The standard number of boost pads is 34, but this map has %d:%s",
61+
len(self.field_info.boost_pads),
62+
"\n".join(map(str, self.field_info.boost_pads)),
63+
)
64+
5765
self.game_state = GameState(self.field_info, self.tick_skip)
5866

5967
self.logger.warning(

0 commit comments

Comments
 (0)