subtr-actor 1.0.0

Rocket League replay transformer
Documentation
use super::*;

const AIR_DRIBBLE_ORIGIN_LABELS: [StatLabel; 2] = [
    StatLabel::new("origin", "ground_to_air"),
    StatLabel::new("origin", "wall_to_air"),
];

fn air_dribble_origin_label(origin: AirDribbleOrigin) -> StatLabel {
    StatLabel::new("origin", origin.as_label_value())
}

#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, ts_rs::TS)]
#[ts(export)]
pub struct AirDribbleStats {
    pub count: u32,
    #[serde(default)]
    pub ground_to_air_count: u32,
    #[serde(default)]
    pub wall_to_air_count: u32,
    #[serde(default)]
    pub total_touch_count: u32,
    #[serde(default)]
    pub max_touch_count: u32,
    pub total_time: f32,
    pub total_straight_line_distance: f32,
    pub total_path_distance: f32,
    pub longest_time: f32,
    pub furthest_distance: f32,
    pub fastest_speed: f32,
    pub speed_sum: f32,
    pub average_horizontal_gap_sum: f32,
    pub average_vertical_gap_sum: f32,
    #[serde(default, skip_serializing_if = "LabeledCounts::is_empty")]
    pub labeled_event_counts: LabeledCounts,
}

impl AirDribbleStats {
    fn count_average(&self, value: f32) -> f32 {
        if self.count == 0 {
            0.0
        } else {
            value / self.count as f32
        }
    }

    pub fn average_time(&self) -> f32 {
        self.count_average(self.total_time)
    }

    pub fn average_straight_line_distance(&self) -> f32 {
        self.count_average(self.total_straight_line_distance)
    }

    pub fn average_path_distance(&self) -> f32 {
        self.count_average(self.total_path_distance)
    }

    pub fn average_speed(&self) -> f32 {
        self.count_average(self.speed_sum)
    }

    pub fn average_touch_count(&self) -> f32 {
        self.count_average(self.total_touch_count as f32)
    }

    pub fn average_horizontal_gap(&self) -> f32 {
        self.count_average(self.average_horizontal_gap_sum)
    }

    pub fn average_vertical_gap(&self) -> f32 {
        self.count_average(self.average_vertical_gap_sum)
    }

    pub(crate) fn apply_event(&mut self, event: &BallCarryEvent) {
        self.record_event(event);
        self.total_time += event.duration;
        self.total_straight_line_distance += event.straight_line_distance;
        self.total_path_distance += event.path_distance;
        self.longest_time = self.longest_time.max(event.duration);
        self.furthest_distance = self.furthest_distance.max(event.straight_line_distance);
        self.fastest_speed = self.fastest_speed.max(event.average_speed);
        self.speed_sum += event.average_speed;
        self.average_horizontal_gap_sum += event.average_horizontal_gap;
        self.average_vertical_gap_sum += event.average_vertical_gap;
        self.total_touch_count += event.touch_count;
        self.max_touch_count = self.max_touch_count.max(event.touch_count);
    }

    fn record_event(&mut self, event: &BallCarryEvent) {
        if let Some(origin) = event.air_dribble_origin {
            self.labeled_event_counts
                .increment([air_dribble_origin_label(origin)]);
        }
        self.sync_legacy_counts();
    }

    pub fn event_count_with_labels(&self, labels: &[StatLabel]) -> u32 {
        self.labeled_event_counts.count_matching(labels)
    }

    pub fn complete_labeled_event_counts(&self) -> LabeledCounts {
        LabeledCounts::complete_from_label_sets(
            &[&AIR_DRIBBLE_ORIGIN_LABELS],
            &self.labeled_event_counts,
        )
    }

    fn sync_legacy_counts(&mut self) {
        self.count = self.labeled_event_counts.total();
        self.ground_to_air_count = self
            .event_count_with_labels(&[air_dribble_origin_label(AirDribbleOrigin::GroundToAir)]);
        self.wall_to_air_count =
            self.event_count_with_labels(&[air_dribble_origin_label(AirDribbleOrigin::WallToAir)]);
    }
}