subtr_actor/stats/analysis_graph/nodes/
continuous_ball_control.rs1use 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 candidate = if frame.dt > 0.0 {
46 BallCarryCalculator::control_candidate(
47 ctx.get::<BallFrameState>()?,
48 ctx.get::<PlayerFrameState>()?,
49 ctx.get::<LivePlayState>()?.is_live_play,
50 touch_state,
51 )
52 } else {
53 None
54 };
55 self.state.completed_sequences.extend(self.tracker.update(
56 frame,
57 candidate,
58 BallCarryCalculator::min_duration_for_kind,
59 ));
60 Ok(())
61 }
62
63 fn finish(&mut self, _ctx: &AnalysisStateContext<'_>) -> SubtrActorResult<()> {
64 if let Some(sequence) = self
65 .tracker
66 .finish(BallCarryCalculator::min_duration_for_kind)
67 {
68 self.state.completed_sequences.push(sequence);
69 }
70 Ok(())
71 }
72
73 fn state(&self) -> &Self::State {
74 &self.state
75 }
76}
77
78pub(crate) fn boxed_default() -> Box<dyn AnalysisNodeDyn> {
79 Box::new(ContinuousBallControlNode::new())
80}