1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
//! # subtr-actor
//!
//! `subtr-actor` turns raw [`boxcars`] replay data into higher-level game
//! state, derived replay events, structured frame payloads, and dense numeric
//! features for analytics and ML workflows.
//!
//! The Rust crate is the source of truth for the replay-processing pipeline.
//! The Python and JavaScript bindings build on the same collector APIs and
//! string-addressable feature registry exposed here.
//!
//! ## Processing model
//!
//! - [`ReplayProcessor`] walks the replay's network frames, models actor state,
//! and tracks derived replay events such as touches, boost pad pickups,
//! dodge refreshes, goals, player stat events, and demolishes.
//! - [`Collector`] is the core extension point. Collectors observe the replay
//! frame by frame and can either process every frame or control sampling via
//! [`TimeAdvance`].
//! - [`ReplayProcessor::process_all`] lets multiple collectors share a single
//! replay pass when you want to build several outputs at once.
//! - [`FrameRateDecorator`] and [`CallbackCollector`] provide lightweight
//! utilities for downsampling a collector or attaching side-effectful hooks
//! such as progress reporting and debugging.
//!
//! ## Primary output layers
//!
//! - [`ReplayDataCollector`] builds a serde-friendly replay payload with frame
//! data, replay metadata, and derived event streams suitable for JSON export
//! and playback UIs.
//! - [`NDArrayCollector`] emits a dense [`::ndarray::Array2`] with replay
//! metadata and headers. It supports both explicit feature adders and the
//! string-based registry exposed through [`NDArrayCollector::from_strings`]
//! and [`NDArrayCollector::from_strings_typed`].
//! - [`StatsCollector`] accumulates graph-backed replay statistics as a
//! module-keyed dynamic payload suitable for builtin module selection and
//! JSON export.
//! - [`StatsTimelineCollector`] accumulates graph-backed replay statistics
//! frame by frame and returns typed snapshots ([`ReplayStatsTimeline`]) for
//! the builtin analysis modules.
//!
//! ## Stats and exports
//!
//! The [`stats`] module houses analysis calculators, graph nodes, stat
//! mechanics helpers, and the exported stat-field model built around
//! [`ExportedStat`].
//!
//! ## Examples
//!
//! ### Collect structured replay data
//!
//! ```no_run
//! use boxcars::ParserBuilder;
//! use subtr_actor::ReplayDataCollector;
//!
//! let bytes = std::fs::read("replay.replay").unwrap();
//! let replay = ParserBuilder::new(&bytes)
//! .must_parse_network_data()
//! .on_error_check_crc()
//! .parse()
//! .unwrap();
//!
//! let replay_data = ReplayDataCollector::new().get_replay_data(&replay).unwrap();
//! println!("frames: {}", replay_data.frame_data.frame_count());
//! println!("touches: {}", replay_data.touch_events.len());
//! ```
//!
//! ### Build a sampled feature matrix
//!
//! ```no_run
//! use boxcars::ParserBuilder;
//! use subtr_actor::{Collector, FrameRateDecorator, NDArrayCollector};
//!
//! let bytes = std::fs::read("replay.replay").unwrap();
//! let replay = ParserBuilder::new(&bytes)
//! .must_parse_network_data()
//! .on_error_check_crc()
//! .parse()
//! .unwrap();
//!
//! let mut collector = NDArrayCollector::<f32>::from_strings(
//! &["BallRigidBody", "CurrentTime"],
//! &["PlayerRigidBody", "PlayerBoost", "PlayerAnyJump"],
//! )
//! .unwrap();
//!
//! FrameRateDecorator::new_from_fps(30.0, &mut collector)
//! .process_replay(&replay)
//! .unwrap();
//!
//! let (meta, features) = collector.get_meta_and_ndarray().unwrap();
//! println!("players: {}", meta.replay_meta.player_count());
//! println!("shape: {:?}", features.raw_dim());
//! ```
//!
//! ### Export typed stats timeline snapshots
//!
//! ```no_run
//! use boxcars::ParserBuilder;
//! use subtr_actor::StatsTimelineCollector;
//!
//! let bytes = std::fs::read("replay.replay").unwrap();
//! let replay = ParserBuilder::new(&bytes)
//! .must_parse_network_data()
//! .on_error_check_crc()
//! .parse()
//! .unwrap();
//!
//! let timeline = StatsTimelineCollector::new().get_replay_data(&replay).unwrap();
//!
//! println!("timeline frames: {}", timeline.frames.len());
//! println!("rush events: {}", timeline.events.rush.len());
//! ```
pub use crate*;
pub use crate*;
pub use crate*;
pub use crate*;
pub use crate*;
pub use crate*;
pub use crate*;
pub use crate*;
pub use crate*;
pub use crate*;
pub use crate*;
pub use crate*;
pub use crate*;