| Crates.io | subtr-actor |
| lib.rs | subtr-actor |
| version | 0.1.8 |
| created_at | 2023-06-12 09:35:31.569615+00 |
| updated_at | 2025-07-16 05:31:29.26415+00 |
| description | Rocket League replay transformer |
| homepage | |
| repository | https://github.com/rlrml/subtr-actor |
| max_upload_size | |
| id | 888015 |
| size | 2,958,913 |
subtr-actor is a versatile library designed to facilitate the
processes of working with and extracting data from Rocket League replays.
Utilizing the powerful boxcars library for parsing, subtr-actor
simplifies (or 'subtracts', as hinted by its name) the underlying
actor-based structure of replay files, making them more accessible and
easier to manipulate.
ReplayProcessor: This struct is at the heart of subtr-actor's
replay processing capabilities. In its main entry point,
ReplayProcessor::process, it pushes network frames from the
boxcars::Replay that it is initialized with through an
ActorStateModeler instance, calling the Collector instance that is
provided as an argument as it does so. The Collector is provided with a
reference to the ReplayProcessor each time it is invoked, which
allows it to use the suite of helper methods which greatly assist in the
navigation of the actor graph and the retrieval of information about the current
game state.
Collector: This trait outlines the blueprint for data collection
from replays. The Collector interfaces with a ReplayProcessor,
handling frame data and guiding the pace of replay progression with
TimeAdvance. It is typically invoked repeatedly through the
ReplayProcessor::process method as the replay is processed frame by
frame.
FrameRateDecorator: This struct decorates a Collector
implementation with a target frame duration, controlling the frame rate of
the replay processing.
subtr-actor also includes implementations of the Collector trait:
NDArrayCollector: This Collector implementation translates
frame-based replay data into a 2 dimensional array in the form of a
::ndarray::Array2 instance. The exact data that is recorded in each
frame can be configured with the FeatureAdder and PlayerFeatureAdder
instances that are provided to its constructor (NDArrayCollector::new).
Extending the exact behavior of NDArrayCollector is thus possible with
user defined FeatureAdder and PlayerFeatureAdder, which is made easy
with the build_global_feature_adder! and build_player_feature_adder!
macros. The ::ndarray::Array2 produced by NDArrayCollector is ideal
for use with machine learning libraries like pytorch and tensorflow.
ReplayDataCollector: This Collector implementation provides
an easy way to get a serializable representation to e.g. json (through serde::Serialize)
representation of the replay. The representation differs from what you might get
from e.g. raw boxcars in that it is not a complicated graph of actor
objects, but instead something more natural where the data associated with each
entity in the game is grouped together.
fn get_json(filepath: std::path::PathBuf) -> anyhow::Result<String> {
let data = std::fs::read(filepath.as_path())?;
let replay = boxcars::ParserBuilder::new(&data)
.must_parse_network_data()
.on_error_check_crc()
.parse()?;
Ok(subtr_actor::ReplayDataCollector::new()
.get_replay_data(&replay)
.map_err(|e| e.variant)?
.as_json()?)
}
::ndarray::Array2In the following example, we demonstrate how to use boxcars,
NDArrayCollector and FrameRateDecorator to write a function that
takes a replay filepath and collections of feature adders and returns a
ReplayMetaWithHeaders along with a ::ndarray::Array2 . The resulting
::ndarray::Array2 would be appropriate for use in a machine learning
context. Note that ReplayProcessor is also used implicitly here in the
Collector::process_replay.
use subtr_actor::*;
fn get_ndarray_with_info_from_replay_filepath(
filepath: std::path::PathBuf,
feature_adders: FeatureAdders<f32>,
player_feature_adders: PlayerFeatureAdders<f32>,
fps: Option<f32>,
) -> anyhow::Result<(ReplayMetaWithHeaders, ::ndarray::Array2<f32>)> {
let data = std::fs::read(filepath.as_path())?;
let replay = boxcars::ParserBuilder::new(&data)
.must_parse_network_data()
.on_error_check_crc()
.parse()?;
let mut collector = NDArrayCollector::new(feature_adders, player_feature_adders);
FrameRateDecorator::new_from_fps(fps.unwrap_or(10.0), &mut collector)
.process_replay(&replay)
.map_err(|e| e.variant)?;
Ok(collector.get_meta_and_ndarray().map_err(|e| e.variant)?)
}
fn get_ndarray_with_default_feature_adders(
filepath: std::path::PathBuf,
) -> anyhow::Result<(ReplayMetaWithHeaders, ::ndarray::Array2<f32>)> {
get_ndarray_with_info_from_replay_filepath(
filepath,
vec![
InterpolatedBallRigidBodyNoVelocities::arc_new(0.003),
CurrentTime::arc_new(),
],
vec![
InterpolatedPlayerRigidBodyNoVelocities::arc_new(0.003),
PlayerBoost::arc_new(),
PlayerAnyJump::arc_new(),
PlayerDemolishedBy::arc_new(),
],
Some(30.0),
)
}
NDArrayCollector::from_stringsIn the second function we see the use of feature adders like
InterpolatedPlayerRigidBodyNoVelocities. The feature adders that are
included with subtr_actor can all be found in the
crate::collector::ndarray module. It is also possible to access these
feature adders by name with strings, which can be useful when implementing
bindings for other languages since those languages may not be able to access
rust structs an instantiate them easily or at all.
pub static DEFAULT_GLOBAL_FEATURE_ADDERS: [&str; 1] = ["BallRigidBody"];
pub static DEFAULT_PLAYER_FEATURE_ADDERS: [&str; 3] =
["PlayerRigidBody", "PlayerBoost", "PlayerAnyJump"];
fn build_ndarray_collector(
global_feature_adders: Option<Vec<String>>,
player_feature_adders: Option<Vec<String>>,
) -> subtr_actor::SubtrActorResult<subtr_actor::NDArrayCollector<f32>> {
let global_feature_adders = global_feature_adders.unwrap_or_else(|| {
DEFAULT_GLOBAL_FEATURE_ADDERS
.iter()
.map(|i| i.to_string())
.collect()
});
let player_feature_adders = player_feature_adders.unwrap_or_else(|| {
DEFAULT_PLAYER_FEATURE_ADDERS
.iter()
.map(|i| i.to_string())
.collect()
});
let global_feature_adders: Vec<&str> = global_feature_adders.iter().map(|s| &s[..]).collect();
let player_feature_adders: Vec<&str> = player_feature_adders.iter().map(|s| &s[..]).collect();
subtr_actor::NDArrayCollector::<f32>::from_strings(
&global_feature_adders,
&player_feature_adders,
)
}