Skip to main content

subtr_actor/stats/analysis_graph/
mod.rs

1#![allow(dead_code)]
2
3use std::collections::HashSet;
4
5use crate::Collector;
6use crate::{SubtrActorError, SubtrActorErrorVariant, SubtrActorResult};
7
8pub mod graph;
9pub use graph::{
10    AnalysisDependency, AnalysisGraph, AnalysisNode, AnalysisNodeDyn, AnalysisStateContext,
11    AnalysisStateRef,
12};
13
14#[macro_use]
15mod node_macros;
16
17mod collector;
18mod nodes;
19
20use crate::stats::calculators::FrameInput;
21
22#[allow(unused_imports)]
23pub use collector::AnalysisNodeCollector;
24#[allow(unused_imports)]
25pub use nodes::*;
26
27pub(crate) fn boxed_analysis_node_by_name(name: &str) -> Option<Box<dyn AnalysisNodeDyn>> {
28    match name {
29        "core" => Some(nodes::match_stats::boxed_default()),
30        "backboard" => Some(nodes::backboard::boxed_default()),
31        "ceiling_shot" => Some(nodes::ceiling_shot::boxed_default()),
32        "double_tap" => Some(nodes::double_tap::boxed_default()),
33        "fifty_fifty" => Some(nodes::fifty_fifty::boxed_default()),
34        "possession" => Some(nodes::possession::boxed_default()),
35        "pressure" => Some(nodes::pressure::boxed_default()),
36        "rush" => Some(nodes::rush::boxed_default()),
37        "touch" => Some(nodes::touch::boxed_default()),
38        "speed_flip" => Some(nodes::speed_flip::boxed_default()),
39        "musty_flick" => Some(nodes::musty_flick::boxed_default()),
40        "dodge_reset" => Some(nodes::dodge_reset::boxed_default()),
41        "ball_carry" => Some(nodes::ball_carry::boxed_default()),
42        "boost" => Some(nodes::boost::boxed_default()),
43        "movement" => Some(nodes::movement::boxed_default()),
44        "positioning" => Some(nodes::positioning::boxed_default()),
45        "powerslide" => Some(nodes::powerslide::boxed_default()),
46        "demo" => Some(nodes::demo::boxed_default()),
47        _ => None,
48    }
49}
50
51pub fn graph_with_builtin_analysis_nodes<I, S>(names: I) -> SubtrActorResult<AnalysisGraph>
52where
53    I: IntoIterator<Item = S>,
54    S: AsRef<str>,
55{
56    let mut graph = AnalysisGraph::new().with_input_state_type::<FrameInput>();
57    graph.push_boxed_node(nodes::live_play::boxed_default());
58    let mut seen = HashSet::new();
59    for name in names {
60        let name = name.as_ref();
61        if !seen.insert(name.to_owned()) {
62            continue;
63        }
64        graph.push_boxed_node(boxed_analysis_node_by_name(name).ok_or_else(|| {
65            SubtrActorError::new(SubtrActorErrorVariant::UnknownStatsModuleName(
66                name.to_owned(),
67            ))
68        })?);
69    }
70    Ok(graph)
71}
72
73pub fn collect_analysis_graph_for_replay(
74    replay: &boxcars::Replay,
75    graph: AnalysisGraph,
76) -> SubtrActorResult<AnalysisGraph> {
77    let collector = collector::AnalysisNodeCollector::new(graph).process_replay(replay)?;
78    Ok(collector.into_graph())
79}
80
81pub fn collect_builtin_analysis_graph_for_replay<I, S>(
82    replay: &boxcars::Replay,
83    names: I,
84) -> SubtrActorResult<AnalysisGraph>
85where
86    I: IntoIterator<Item = S>,
87    S: AsRef<str>,
88{
89    collect_analysis_graph_for_replay(replay, graph_with_builtin_analysis_nodes(names)?)
90}
91
92pub fn all_analysis_nodes() -> Vec<Box<dyn AnalysisNodeDyn>> {
93    vec![
94        nodes::backboard::boxed_default(),
95        nodes::ball_carry::boxed_default(),
96        nodes::boost::boxed_default(),
97        nodes::ceiling_shot::boxed_default(),
98        nodes::demo::boxed_default(),
99        nodes::dodge_reset::boxed_default(),
100        nodes::double_tap::boxed_default(),
101        nodes::fifty_fifty::boxed_default(),
102        nodes::match_stats::boxed_default(),
103        nodes::movement::boxed_default(),
104        nodes::musty_flick::boxed_default(),
105        nodes::positioning::boxed_default(),
106        nodes::possession::boxed_default(),
107        nodes::powerslide::boxed_default(),
108        nodes::pressure::boxed_default(),
109        nodes::rush::boxed_default(),
110        nodes::settings::boxed_default(),
111        nodes::speed_flip::boxed_default(),
112        nodes::touch::boxed_default(),
113    ]
114}
115
116pub fn graph_with_all_analysis_nodes() -> AnalysisGraph {
117    let mut graph = AnalysisGraph::new().with_input_state_type::<FrameInput>();
118    graph.push_boxed_node(nodes::live_play::boxed_default());
119    for node in all_analysis_nodes() {
120        graph.push_boxed_node(node);
121    }
122    graph
123}
124
125#[cfg(test)]
126#[path = "module_tests.rs"]
127mod tests;