subtr_actor/processor/
bootstrap.rs1use super::*;
2
3impl<'a> ReplayProcessor<'a> {
4 pub(crate) fn set_player_order_from_headers(&mut self) -> SubtrActorResult<()> {
6 let _player_stats = self
7 .replay
8 .properties
9 .iter()
10 .find(|(key, _)| key == "PlayerStats")
11 .ok_or_else(|| {
12 SubtrActorError::new(SubtrActorErrorVariant::PlayerStatsHeaderNotFound)
13 })?;
14 SubtrActorError::new_result(SubtrActorErrorVariant::PlayerStatsHeaderNotFound)
16 }
17
18 pub fn process_long_enough_to_get_actor_ids(&mut self) -> SubtrActorResult<()> {
35 let mut handler = |_p: &ReplayProcessor, _f: &boxcars::Frame, n: usize, _current_time| {
36 if n > 10 * 30 {
38 SubtrActorError::new_result(SubtrActorErrorVariant::FinishProcessingEarly)
39 } else {
40 Ok(TimeAdvance::NextFrame)
41 }
42 };
43 let process_result = self.process(&mut handler);
44 if let Some(SubtrActorErrorVariant::FinishProcessingEarly) =
45 process_result.as_ref().err().map(|e| e.variant.clone())
46 {
47 Ok(())
48 } else {
49 process_result
50 }
51 }
52
53 pub(crate) fn set_player_order_from_frames(&mut self) -> SubtrActorResult<()> {
55 self.process_long_enough_to_get_actor_ids()?;
56 let player_to_team_0: HashMap<PlayerId, bool> = self
57 .player_to_actor_id
58 .keys()
59 .filter_map(|player_id| {
60 self.get_player_is_team_0(player_id)
61 .ok()
62 .map(|is_team_0| (player_id.clone(), is_team_0))
63 })
64 .collect();
65
66 let (team_zero, team_one): (Vec<_>, Vec<_>) = player_to_team_0
67 .keys()
68 .cloned()
69 .partition(|player_id| *player_to_team_0.get(player_id).unwrap());
71
72 self.team_zero = team_zero;
73 self.team_one = team_one;
74
75 self.team_zero
76 .sort_by(|a, b| format!("{a:?}").cmp(&format!("{b:?}")));
77 self.team_one
78 .sort_by(|a, b| format!("{a:?}").cmp(&format!("{b:?}")));
79
80 self.reset();
81 Ok(())
82 }
83
84 pub fn check_player_id_set(&self) -> SubtrActorResult<()> {
86 let known_players =
87 std::collections::HashSet::<_>::from_iter(self.player_to_actor_id.keys());
88 let original_players =
89 std::collections::HashSet::<_>::from_iter(self.iter_player_ids_in_order());
90
91 if original_players != known_players {
92 SubtrActorError::new_result(SubtrActorErrorVariant::InconsistentPlayerSet {
93 found: known_players.into_iter().cloned().collect(),
94 original: original_players.into_iter().cloned().collect(),
95 })
96 } else {
97 Ok(())
98 }
99 }
100
101 pub fn process_and_get_replay_meta(&mut self) -> SubtrActorResult<ReplayMeta> {
110 if self.player_to_actor_id.is_empty() {
111 self.process_long_enough_to_get_actor_ids()?;
112 }
113 self.get_replay_meta()
114 }
115
116 pub fn get_replay_meta(&self) -> SubtrActorResult<ReplayMeta> {
123 let empty_player_stats = Vec::new();
124 let player_stats = if let Some((_, boxcars::HeaderProp::Array(per_player))) = self
125 .replay
126 .properties
127 .iter()
128 .find(|(key, _)| key == "PlayerStats")
129 {
130 per_player
131 } else {
132 &empty_player_stats
133 };
134 let known_count = self.iter_player_ids_in_order().count();
135 if player_stats.len() != known_count {
136 log::warn!(
137 "Replay does not have player stats for all players. encountered {:?} {:?}",
138 known_count,
139 player_stats.len()
140 )
141 }
142 let get_player_info = |player_id| {
143 let fallback_name = String::new();
144 let stats = self
145 .get_player_name(player_id)
146 .ok()
147 .and_then(|name| find_player_stats(player_id, &name, player_stats).ok())
148 .or_else(|| find_player_stats(player_id, &fallback_name, player_stats).ok());
149 let name = self
150 .get_player_name(player_id)
151 .ok()
152 .or_else(|| {
153 stats.as_ref().and_then(|stats| {
154 stats.get("Name").and_then(|prop| match prop {
155 boxcars::HeaderProp::Str(name) => Some(name.clone()),
156 _ => None,
157 })
158 })
159 })
160 .unwrap_or_else(|| format!("{player_id:?}"));
161 Ok(PlayerInfo {
162 name,
163 stats,
164 remote_id: player_id.clone(),
165 })
166 };
167 let team_zero: SubtrActorResult<Vec<PlayerInfo>> =
168 self.team_zero.iter().map(get_player_info).collect();
169 let team_one: SubtrActorResult<Vec<PlayerInfo>> =
170 self.team_one.iter().map(get_player_info).collect();
171 Ok(ReplayMeta {
172 team_zero: team_zero?,
173 team_one: team_one?,
174 all_headers: self.replay.properties.clone(),
175 })
176 }
177}