1use rlbot_flat::flat::{
2 BallPrediction, ConnectionSettings, CoreMessage, FieldInfo, GamePacket, InitComplete,
3 MatchComm, MatchConfiguration, PingResponse, RenderingStatus,
4};
5
6use crate::{RLBotConnection, StartingInfo, util::PacketQueue};
7
8use super::AgentError;
9
10#[allow(unused_variables)]
11pub trait ScriptAgent {
21 fn new(
27 agent_id: String,
28 match_configuration: MatchConfiguration,
29 field_info: FieldInfo,
30 packet_queue: &mut PacketQueue,
31 ) -> Self;
32 fn tick(&mut self, game_packet: GamePacket, packet_queue: &mut PacketQueue);
38 fn on_match_comm(&mut self, match_comm: MatchComm, packet_queue: &mut PacketQueue) {}
42 fn on_ball_prediction(
47 &mut self,
48 ball_prediction: BallPrediction,
49 packet_queue: &mut PacketQueue,
50 ) {
51 }
52 fn on_rendering_status(
54 &mut self,
55 rendering_status: RenderingStatus,
56 packet_queue: &mut PacketQueue,
57 ) {
58 }
59 fn on_ping_response(&mut self, ping: PingResponse, packet_queue: &mut PacketQueue) {}
61}
62
63pub fn run_script_agent<T: ScriptAgent>(
70 agent_id: String,
71 wants_ball_predictions: bool,
72 wants_comms: bool,
73 mut connection: RLBotConnection,
74) -> Result<(), AgentError> {
75 connection.send_packet(ConnectionSettings {
76 agent_id: agent_id.clone(),
77 wants_ball_predictions,
78 wants_comms,
79 close_between_matches: true,
80 })?;
81
82 let StartingInfo {
83 controllable_team_info: _,
84 match_configuration,
85 field_info,
86 } = connection.get_starting_info()?;
87
88 let mut outgoing_queue = PacketQueue::default();
89 let mut agent = T::new(
90 agent_id,
91 match_configuration,
92 field_info,
93 &mut outgoing_queue,
94 );
95
96 outgoing_queue.push(InitComplete {});
97 connection.send_packets_enum(outgoing_queue.empty().into_iter())?;
98
99 while let Ok(packet) = connection.recv_packet() {
100 match packet {
101 CoreMessage::DisconnectSignal(_) => break,
102 CoreMessage::GamePacket(x) => {
103 agent.tick(*x, &mut outgoing_queue);
104 }
105 CoreMessage::MatchComm(x) => {
106 agent.on_match_comm(*x, &mut outgoing_queue);
107 }
108 CoreMessage::BallPrediction(x) => {
109 agent.on_ball_prediction(*x, &mut outgoing_queue);
110 }
111 CoreMessage::RenderingStatus(x) => {
112 agent.on_rendering_status(*x, &mut outgoing_queue);
113 }
114 CoreMessage::PingResponse(x) => {
115 agent.on_ping_response(*x, &mut outgoing_queue);
116 }
117 CoreMessage::PingRequest(x) => {
118 outgoing_queue.push(PingResponse { cookie: x.cookie });
119 }
120 CoreMessage::FieldInfo(_)
121 | CoreMessage::MatchConfiguration(_)
122 | CoreMessage::ControllableTeamInfo(_) => {
123 unreachable!("Unexpected packet; should not be able to receive this packet type.")
124 }
125 }
126
127 connection.send_packets_enum(outgoing_queue.empty().into_iter())?;
128 }
129
130 Ok(())
131}