subtr_actor_spec/collector/
replay_data.rs

1use boxcars;
2use serde::Serialize;
3
4use crate::*;
5
6#[derive(Debug, Clone, PartialEq, Serialize)]
7pub enum BallFrame {
8    Empty,
9    Data { rigid_body: boxcars::RigidBody },
10}
11
12impl BallFrame {
13    fn new_from_processor(processor: &ReplayProcessor, current_time: f32) -> Self {
14        if processor.get_ignore_ball_syncing().unwrap_or(false) {
15            Self::Empty
16        } else if let Ok(rigid_body) = processor.get_interpolated_ball_rigid_body(current_time, 0.0)
17        {
18            Self::new_from_rigid_body(rigid_body)
19        } else {
20            Self::Empty
21        }
22    }
23
24    fn new_from_rigid_body(rigid_body: boxcars::RigidBody) -> Self {
25        if rigid_body.sleeping {
26            Self::Empty
27        } else {
28            Self::Data {
29                rigid_body: rigid_body.clone(),
30            }
31        }
32    }
33}
34
35#[derive(Debug, Clone, PartialEq, Serialize)]
36pub enum PlayerFrame {
37    Empty,
38    Data {
39        rigid_body: boxcars::RigidBody,
40        boost_amount: f32,
41        boost_active: bool,
42        jump_active: bool,
43        double_jump_active: bool,
44        dodge_active: bool,
45    },
46}
47
48impl PlayerFrame {
49    fn new_from_processor(
50        processor: &ReplayProcessor,
51        player_id: &PlayerId,
52        current_time: f32,
53    ) -> SubtrActorResult<Self> {
54        let rigid_body =
55            processor.get_interpolated_player_rigid_body(player_id, current_time, 0.0)?;
56
57        if rigid_body.sleeping {
58            return Ok(PlayerFrame::Empty);
59        }
60
61        let boost_amount = processor.get_player_boost_level(player_id)?;
62        let boost_active = processor.get_boost_active(player_id).unwrap_or(0) % 2 == 1;
63        let jump_active = processor.get_jump_active(player_id).unwrap_or(0) % 2 == 1;
64        let double_jump_active = processor.get_double_jump_active(player_id).unwrap_or(0) % 2 == 1;
65        let dodge_active = processor.get_dodge_active(player_id).unwrap_or(0) % 2 == 1;
66
67        Ok(Self::from_data(
68            rigid_body,
69            boost_amount,
70            boost_active,
71            jump_active,
72            double_jump_active,
73            dodge_active,
74        ))
75    }
76
77    fn from_data(
78        rigid_body: boxcars::RigidBody,
79        boost_amount: f32,
80        boost_active: bool,
81        jump_active: bool,
82        double_jump_active: bool,
83        dodge_active: bool,
84    ) -> Self {
85        if rigid_body.sleeping {
86            Self::Empty
87        } else {
88            Self::Data {
89                rigid_body,
90                boost_amount,
91                boost_active,
92                jump_active,
93                double_jump_active,
94                dodge_active,
95            }
96        }
97    }
98}
99
100#[derive(Debug, Clone, PartialEq, Serialize)]
101pub struct PlayerData {
102    frames: Vec<PlayerFrame>,
103}
104
105impl PlayerData {
106    fn new() -> Self {
107        Self { frames: Vec::new() }
108    }
109
110    fn add_frame(&mut self, frame_index: usize, frame: PlayerFrame) {
111        let empty_frames_to_add = frame_index - self.frames.len();
112        if empty_frames_to_add > 0 {
113            for _ in 0..empty_frames_to_add {
114                self.frames.push(PlayerFrame::Empty)
115            }
116        }
117        self.frames.push(frame)
118    }
119}
120
121#[derive(Debug, Clone, PartialEq, Serialize)]
122pub struct BallData {
123    frames: Vec<BallFrame>,
124}
125
126impl BallData {
127    fn add_frame(&mut self, frame_index: usize, frame: BallFrame) {
128        let empty_frames_to_add = frame_index - self.frames.len();
129        if empty_frames_to_add > 0 {
130            for _ in 0..empty_frames_to_add {
131                self.frames.push(BallFrame::Empty)
132            }
133        }
134        self.frames.push(frame)
135    }
136}
137
138#[derive(Debug, Clone, PartialEq, Serialize)]
139pub struct MetadataFrame {
140    pub time: f32,
141    pub seconds_remaining: i32,
142}
143
144impl MetadataFrame {
145    fn new_from_processor(processor: &ReplayProcessor, time: f32) -> SubtrActorResult<Self> {
146        Ok(Self::new(time, processor.get_seconds_remaining()?))
147    }
148
149    fn new(time: f32, seconds_remaining: i32) -> Self {
150        MetadataFrame {
151            time,
152            seconds_remaining,
153        }
154    }
155}
156
157#[derive(Debug, Clone, PartialEq, Serialize)]
158pub struct FrameData {
159    pub ball_data: BallData,
160    pub players: Vec<(PlayerId, PlayerData)>,
161    pub metadata_frames: Vec<MetadataFrame>,
162}
163
164#[derive(Debug, Clone, PartialEq, Serialize)]
165pub struct ReplayData {
166    pub frame_data: FrameData,
167    pub meta: ReplayMeta,
168    pub demolish_infos: Vec<DemolishInfo>,
169}
170
171impl ReplayData {
172    pub fn as_json(&self) -> Result<String, serde_json::Error> {
173        serde_json::to_string(self)
174    }
175}
176
177impl FrameData {
178    fn new() -> Self {
179        FrameData {
180            ball_data: BallData { frames: Vec::new() },
181            players: Vec::new(),
182            metadata_frames: Vec::new(),
183        }
184    }
185
186    fn add_frame(
187        &mut self,
188        frame_metadata: MetadataFrame,
189        ball_frame: BallFrame,
190        player_frames: Vec<(PlayerId, PlayerFrame)>,
191    ) -> SubtrActorResult<()> {
192        let frame_index = self.metadata_frames.len();
193        self.metadata_frames.push(frame_metadata);
194        self.ball_data.add_frame(frame_index, ball_frame);
195        for (player_id, frame) in player_frames {
196            self.players
197                .get_entry(player_id)
198                .or_insert_with(|| PlayerData::new())
199                .add_frame(frame_index, frame)
200        }
201        Ok(())
202    }
203}
204
205pub struct ReplayDataCollector {
206    frame_data: FrameData,
207}
208
209impl ReplayDataCollector {
210    pub fn new() -> Self {
211        ReplayDataCollector {
212            frame_data: FrameData::new(),
213        }
214    }
215
216    pub fn get_frame_data(self) -> FrameData {
217        self.frame_data
218    }
219
220    pub fn get_replay_data(mut self, replay: &boxcars::Replay) -> SubtrActorResult<ReplayData> {
221        let mut processor = ReplayProcessor::new(replay)?;
222        processor.process(&mut self)?;
223        let meta = processor.get_replay_meta()?;
224        Ok(ReplayData {
225            meta,
226            demolish_infos: processor.demolishes,
227            frame_data: self.get_frame_data(),
228        })
229    }
230
231    fn get_player_frames(
232        &self,
233        processor: &ReplayProcessor,
234        current_time: f32,
235    ) -> SubtrActorResult<Vec<(PlayerId, PlayerFrame)>> {
236        Ok(processor
237            .iter_player_ids_in_order()
238            .map(|player_id| {
239                (
240                    player_id.clone(),
241                    PlayerFrame::new_from_processor(processor, player_id, current_time)
242                        .unwrap_or_else(|_err| PlayerFrame::Empty),
243                )
244            })
245            .collect())
246    }
247}
248
249impl Collector for ReplayDataCollector {
250    fn process_frame(
251        &mut self,
252        processor: &ReplayProcessor,
253        _frame: &boxcars::Frame,
254        _frame_number: usize,
255        current_time: f32,
256    ) -> SubtrActorResult<TimeAdvance> {
257        let metadata_frame = MetadataFrame::new_from_processor(processor, current_time)?;
258        let ball_frame = BallFrame::new_from_processor(processor, current_time);
259        let player_frames = self.get_player_frames(processor, current_time)?;
260        self.frame_data
261            .add_frame(metadata_frame, ball_frame, player_frames)?;
262        Ok(TimeAdvance::NextFrame)
263    }
264}