subtr_actor/stats/calculators/
powerslide.rs1use super::*;
2
3#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, ts_rs::TS)]
4#[ts(export)]
5pub struct PowerslideStats {
6 pub total_duration: f32,
7 pub press_count: u32,
8}
9
10impl PowerslideStats {
11 pub fn average_duration(&self) -> f32 {
12 if self.press_count == 0 {
13 0.0
14 } else {
15 self.total_duration / self.press_count as f32
16 }
17 }
18}
19
20#[derive(Debug, Clone, Default)]
21pub struct PowerslideCalculator {
22 player_stats: HashMap<PlayerId, PowerslideStats>,
23 team_zero_stats: PowerslideStats,
24 team_one_stats: PowerslideStats,
25 last_active: HashMap<PlayerId, bool>,
26}
27
28impl PowerslideCalculator {
29 pub fn new() -> Self {
30 Self::default()
31 }
32
33 pub fn player_stats(&self) -> &HashMap<PlayerId, PowerslideStats> {
34 &self.player_stats
35 }
36
37 pub fn team_zero_stats(&self) -> &PowerslideStats {
38 &self.team_zero_stats
39 }
40
41 pub fn team_one_stats(&self) -> &PowerslideStats {
42 &self.team_one_stats
43 }
44
45 fn is_effective_powerslide(player: &PlayerSample) -> bool {
46 player.powerslide_active
47 && player
48 .position()
49 .map(|position| position.z <= POWERSLIDE_MAX_Z_THRESHOLD)
50 .unwrap_or(false)
51 }
52
53 pub fn update(
54 &mut self,
55 frame: &FrameInfo,
56 players: &PlayerFrameState,
57 live_play: bool,
58 ) -> SubtrActorResult<()> {
59 for player in &players.players {
60 let effective_powerslide = Self::is_effective_powerslide(player);
61 let previous_active = self
62 .last_active
63 .get(&player.player_id)
64 .copied()
65 .unwrap_or(false);
66 let stats = self
67 .player_stats
68 .entry(player.player_id.clone())
69 .or_default();
70 let team_stats = if player.is_team_0 {
71 &mut self.team_zero_stats
72 } else {
73 &mut self.team_one_stats
74 };
75
76 if live_play && effective_powerslide {
77 stats.total_duration += frame.dt;
78 team_stats.total_duration += frame.dt;
79 }
80
81 if live_play && effective_powerslide && !previous_active {
82 stats.press_count += 1;
83 team_stats.press_count += 1;
84 }
85
86 self.last_active
87 .insert(player.player_id.clone(), effective_powerslide);
88 }
89 Ok(())
90 }
91}