Skip to main content

subtr_actor/stats/analysis_graph/nodes/
continuous_ball_control.rs

1use super::*;
2use crate::stats::calculators::*;
3use crate::*;
4
5pub struct ContinuousBallControlNode {
6    tracker: ContinuousBallControlTracker<BallCarryKind>,
7    state: ContinuousBallControlState,
8}
9
10impl ContinuousBallControlNode {
11    pub fn new() -> Self {
12        Self {
13            tracker: ContinuousBallControlTracker::default(),
14            state: ContinuousBallControlState::default(),
15        }
16    }
17}
18
19impl Default for ContinuousBallControlNode {
20    fn default() -> Self {
21        Self::new()
22    }
23}
24
25impl AnalysisNode for ContinuousBallControlNode {
26    type State = ContinuousBallControlState;
27
28    fn name(&self) -> &'static str {
29        "continuous_ball_control"
30    }
31
32    fn dependencies(&self) -> Vec<AnalysisDependency> {
33        vec![
34            frame_info_dependency(),
35            ball_frame_state_dependency(),
36            player_frame_state_dependency(),
37            touch_state_dependency(),
38            live_play_dependency(),
39        ]
40    }
41
42    fn evaluate(&mut self, ctx: &AnalysisStateContext<'_>) -> SubtrActorResult<()> {
43        let frame = ctx.get::<FrameInfo>()?;
44        let touch_state = ctx.get::<TouchState>()?;
45        let players = ctx.get::<PlayerFrameState>()?;
46        let candidate = if frame.dt > 0.0 {
47            BallCarryCalculator::control_candidate(
48                ctx.get::<BallFrameState>()?,
49                players,
50                ctx.get::<LivePlayState>()?.is_live_play,
51                touch_state,
52            )
53        } else {
54            None
55        };
56        let player_statuses = BallCarryCalculator::control_player_statuses(players);
57        let touches = BallCarryCalculator::control_touches(touch_state, players);
58        self.state.completed_sequences.extend(self.tracker.update(
59            frame,
60            candidate,
61            &player_statuses,
62            &touches,
63            BallCarryCalculator::min_duration_for_kind,
64            BallCarryCalculator::kind_requires_airborne,
65        ));
66        Ok(())
67    }
68
69    fn finish(&mut self, _ctx: &AnalysisStateContext<'_>) -> SubtrActorResult<()> {
70        if let Some(sequence) = self
71            .tracker
72            .finish(BallCarryCalculator::min_duration_for_kind)
73        {
74            self.state.completed_sequences.push(sequence);
75        }
76        Ok(())
77    }
78
79    fn state(&self) -> &Self::State {
80        &self.state
81    }
82}
83
84pub(crate) fn boxed_default() -> Box<dyn AnalysisNodeDyn> {
85    Box::new(ContinuousBallControlNode::new())
86}