subtr_actor/
lib.rs

1#![allow(clippy::result_large_err)]
2
3//! # subtr-actor
4//!
5//! [`subtr-actor`](crate) is a versatile library designed to facilitate the
6//! processes of working with and extracting data from Rocket League replays.
7//! Utilizing the powerful [`boxcars`] library for parsing, subtr-actor
8//! simplifies (or 'subtracts', as hinted by its name) the underlying
9//! actor-based structure of replay files, making them more accessible and
10//! easier to manipulate.
11//!
12//! ## Overview of Key Components
13//!
14//! - **[`ReplayProcessor`]**: This struct is at the heart of subtr-actor's
15//!   replay processing capabilities. In its main entry point,
16//!   [`ReplayProcessor::process`], it pushes network frames from the
17//!   [`boxcars::Replay`] that it is initialized with though an
18//!   [`ActorStateModeler`] instance, calling the [`Collector`] instance that is
19//!   provided as an argument as it does so. The [`Collector`] is provided with a
20//!   reference to the [`ReplayProcessor`] each time the it is invoked, which
21//!   allows it to use the suite of helper methods which greatly assist in the
22//!   navigation of the actor graph and the retrieval of information about the
23//!   current game state.
24//!
25//! - **[`Collector`]**: This trait outlines the blueprint for data collection
26//!   from replays. The [`Collector`] interfaces with a [`ReplayProcessor`],
27//!   handling frame data and guiding the pace of replay progression with
28//!   [`TimeAdvance`]. It is typically invoked repeatedly through the
29//!   [`ReplayProcessor::process`] method as the replay is processed frame by
30//!   frame.
31//!
32//! - **[`FrameRateDecorator`]**: This struct decorates a [`Collector`]
33//!   implementation with a target frame duration, controlling the frame rate of
34//!   the replay processing.
35//!
36//! ### Collector implementations
37//!
38//! [`subtr-actor`](crate) also includes implementations of the [`Collector`] trait:
39//!
40//! - **[`NDArrayCollector`]**: This [`Collector`] implementations translates
41//!   frame-based replay data into a 2 dimensional array in the form of a
42//!   [`::ndarray::Array2`] instance. The exact data that is recorded in each
43//!   frame can be configured with the [`FeatureAdder`] and [`PlayerFeatureAdder`]
44//!   instances that are provided to its constructor ([`NDArrayCollector::new`]).
45//!   Extending the exact behavior of [`NDArrayCollector`] is thus possible with
46//!   user defined [`FeatureAdder`] and [`PlayerFeatureAdder`], which is made easy
47//!   with the [`build_global_feature_adder!`] and [`build_player_feature_adder!`]
48//!   macros. The [`::ndarray::Array2`] produced by [`NDArrayCollector`] is ideal
49//!   for use with machine learning libraries like pytorch and tensorflow.
50//!
51//! - **[`ReplayDataCollector`]**: This [`Collector`] implementation provides an
52//!   easy way to get a serializable to e.g. json (though [`serde::Serialize`])
53//!   representation of the replay. The representation differs from what you might
54//!   get from e.g. raw [`boxcars`] in that it is not a complicated graph of actor
55//!   objects, but instead something more natural where the data associated with
56//!   each entity in the game is grouped together.
57//!
58//! ## Examples
59//!
60//! ### Getting JSON
61//!
62//! ```
63//! fn get_json(filepath: std::path::PathBuf) -> anyhow::Result<String> {
64//!     let data = std::fs::read(filepath.as_path())?;
65//!     let replay = boxcars::ParserBuilder::new(&data)
66//!         .must_parse_network_data()
67//!         .on_error_check_crc()
68//!         .parse()?;
69//!     Ok(subtr_actor::ReplayDataCollector::new()
70//!         .get_replay_data(&replay)
71//!         .map_err(|e| e.variant)?
72//!         .as_json()?)
73//! }
74//! ```
75//!
76//! ### Getting a [`::ndarray::Array2`]
77//!
78//! In the following example, we demonstrate how to use [`boxcars`],
79//! [`NDArrayCollector`] and [`FrameRateDecorator`] to write a function that
80//! takes a replay filepath and collections of features adders and returns a
81//! [`ReplayMetaWithHeaders`] along with a [`::ndarray::Array2`] . The resulting
82//! [`::ndarray::Array2`] would be appropriate for use in a machine learning
83//! context. Note that [`ReplayProcessor`] is also used implicitly here in the
84//! [`Collector::process_replay`]
85//!
86//! ```
87//! use subtr_actor::*;
88//!
89//! fn get_ndarray_with_info_from_replay_filepath(
90//!     filepath: std::path::PathBuf,
91//!     feature_adders: FeatureAdders<f32>,
92//!     player_feature_adders: PlayerFeatureAdders<f32>,
93//!     fps: Option<f32>,
94//! ) -> anyhow::Result<(ReplayMetaWithHeaders, ::ndarray::Array2<f32>)> {
95//!     let data = std::fs::read(filepath.as_path())?;
96//!     let replay = boxcars::ParserBuilder::new(&data)
97//!         .must_parse_network_data()
98//!         .on_error_check_crc()
99//!         .parse()?;
100//!
101//!     let mut collector = NDArrayCollector::new(feature_adders, player_feature_adders);
102//!
103//!     FrameRateDecorator::new_from_fps(fps.unwrap_or(10.0), &mut collector)
104//!         .process_replay(&replay)
105//!         .map_err(|e| e.variant)?;
106//!
107//!     Ok(collector.get_meta_and_ndarray().map_err(|e| e.variant)?)
108//! }
109//!
110//! fn get_ndarray_with_default_feature_adders(
111//!     filepath: std::path::PathBuf,
112//! ) -> anyhow::Result<(ReplayMetaWithHeaders, ::ndarray::Array2<f32>)> {
113//!     get_ndarray_with_info_from_replay_filepath(
114//!         filepath,
115//!         vec![
116//!             InterpolatedBallRigidBodyNoVelocities::arc_new(0.003),
117//!             CurrentTime::arc_new(),
118//!         ],
119//!         vec![
120//!             InterpolatedPlayerRigidBodyNoVelocities::arc_new(0.003),
121//!             PlayerBoost::arc_new(),
122//!             PlayerAnyJump::arc_new(),
123//!             PlayerDemolishedBy::arc_new(),
124//!         ],
125//!         Some(30.0),
126//!     )
127//! }
128//! ```
129//!
130//! ### Using [`NDArrayCollector::from_strings`]
131//!
132//! In the second function in the example above, we see the use of feature
133//! adders like [`InterpolatedPlayerRigidBodyNoVelocities`]. The feature adders
134//! that are included with [`subtr_actor`](crate) can all be found in the
135//! [`crate::collector::ndarray`] module. It is also possible to access these
136//! feature adders by name with strings, which can be useful when implementing
137//! bindings for other languages since those languages may not be able to access
138//! rust structs an instantiate them easily or at all.
139//!
140//! ```
141//! pub static DEFAULT_GLOBAL_FEATURE_ADDERS: [&str; 1] = ["BallRigidBody"];
142//!
143//! pub static DEFAULT_PLAYER_FEATURE_ADDERS: [&str; 3] =
144//!     ["PlayerRigidBody", "PlayerBoost", "PlayerAnyJump"];
145//!
146//! fn build_ndarray_collector(
147//!     global_feature_adders: Option<Vec<String>>,
148//!     player_feature_adders: Option<Vec<String>>,
149//! ) -> subtr_actor::SubtrActorResult<subtr_actor::NDArrayCollector<f32>> {
150//!     let global_feature_adders = global_feature_adders.unwrap_or_else(|| {
151//!         DEFAULT_GLOBAL_FEATURE_ADDERS
152//!             .iter()
153//!             .map(|i| i.to_string())
154//!             .collect()
155//!     });
156//!     let player_feature_adders = player_feature_adders.unwrap_or_else(|| {
157//!         DEFAULT_PLAYER_FEATURE_ADDERS
158//!             .iter()
159//!             .map(|i| i.to_string())
160//!             .collect()
161//!     });
162//!     let global_feature_adders: Vec<&str> = global_feature_adders.iter().map(|s| &s[..]).collect();
163//!     let player_feature_adders: Vec<&str> = player_feature_adders.iter().map(|s| &s[..]).collect();
164//!     subtr_actor::NDArrayCollector::<f32>::from_strings(
165//!         &global_feature_adders,
166//!         &player_feature_adders,
167//!     )
168//! }
169//! ```
170
171pub mod actor_state;
172pub mod collector;
173pub mod constants;
174pub mod error;
175pub mod processor;
176pub mod util;
177
178#[cfg(test)]
179mod util_test;
180
181pub use crate::actor_state::*;
182pub use crate::collector::*;
183pub use crate::constants::*;
184pub use crate::error::*;
185pub use crate::processor::*;
186pub use crate::util::*;