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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
//! `subtr-actor` turns raw [`boxcars`](https://docs.rs/boxcars) replay data into
//! higher-level game state, derived replay events, structured frame payloads, and
//! dense numeric features for analytics and ML workflows.
//!
//! - **Higher-level game state** modeled from the raw actor graph
//! - **Frame-by-frame structured data** ready for JSON export and playback UIs
//! - **Dense numeric feature matrices** for ML, built from a string-addressable
//! feature registry
//! - **Derived events and cumulative stats** — touches, boost pickups, dodge
//! refreshes, goals, demolishes, and more
//! - **One pipeline, three languages** — the same Rust core drives the Python and
//! JavaScript/WASM bindings
//!
//! ## 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.
//! - `StatsTimelineEventCollector` accumulates graph-backed replay statistics
//! as event streams plus lightweight frame scaffolding. This is the preferred
//! timeline export when callers do not need to serialize full per-frame
//! partial sums.
//! - `StatsTimelineCollector` preserves the legacy full snapshot timeline
//! form (`ReplayStatsTimeline`) for parity checks and compatibility.
//!
//! ## Stats and exports
//!
//! The `stats` module houses analysis calculators, graph nodes, stat
//! event calculators, and the labeled stat-aggregation types
//! (`LabeledCounts`, `LabeledFloatSums`) consumed by the stats collectors.
//!
//! ## Architecture / module map
//!
//! Read top-down — each module's own documentation expands on the summary
//! here and links to the collections of implementations it contains.
//!
//! - [`processor`] — the replay-walking core. [`ReplayProcessor`] models actor
//! state from `boxcars` network frames and tracks derived events, applying a
//! sequence of per-frame state updaters.
//! - [`collector`] — the output layer. The [`Collector`] trait is the extension
//! point; built-in collectors are [`ReplayDataCollector`] (structured frames),
//! [`NDArrayCollector`] ([numeric features][collector::ndarray]), and the
//! stats-timeline collectors ([`collector::stats`]).
//! - [`stats`] — the analysis layer. A dependency graph of
//! [analysis nodes][stats::analysis_graph] wraps
//! [gameplay-event calculators][StatsEvent] that detect mechanics; results
//! land in accumulators and the [exported stat-field model][stats::export].
//! - [`replay_model`] / [`replay_meta`] — the serde-friendly higher-level game
//! state and replay metadata produced for export and playback UIs.
//! - [`interop`] — bindings-facing helpers shared by the Python and
//! JavaScript/WASM wrappers (e.g. the replay-player manifest).
//! - [`util`] — geometry, search, and small data-structure helpers used
//! throughout the crate.
//!
//! ## Where to find collections of implementations
//!
//! Several parts of the crate are large families of similar types. Each has a
//! catalog in its module documentation, and the shared trait's *Implementors*
//! list is a second way to browse them:
//!
//! | Collection | Module | Shared trait / registry |
//! |---|---|---|
//! | Gameplay-event calculators | [`stats::analysis_graph`] | [`StatsEvent`] |
//! | Analysis-graph nodes | [`stats::analysis_graph`] | [`AnalysisNode`](stats::analysis_graph::AnalysisNode) |
//! | Stat accumulators | [`stats::accumulators`] | (plain accumulation structs) |
//! | Exported stat fields | [`stats::export`] | [`StatFieldProvider`] |
//! | NDArray feature adders | [`collector::ndarray`] | [`FeatureAdder`] family + string registry |
//! | Processor state updaters | [`processor`] | (`impl ReplayProcessor` methods) |
//!
//! ## In-depth guides
//!
//! Longer prose guides are rendered into the API docs under [`guides`]:
//!
//! - [`guides::calculators_and_analysis_nodes`] — the stats runtime DAG layout.
//! - [`guides::stat_confidence`] — how to read exported-stat confidence levels.
//! - [`guides::replay_format_evolution`] — replay-format changes that matter
//! to parsing.
//!
//! ## 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 compact event-backed stats timeline
//!
//! ```no_run
//! use boxcars::ParserBuilder;
//! use subtr_actor::StatsTimelineEventCollector;
//!
//! 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 = StatsTimelineEventCollector::new()
//! .get_replay_stats_timeline_scaffold(&replay)
//! .unwrap();
//!
//! println!("timeline frames: {}", timeline.frames.len());
//! let rush_events = timeline
//! .events
//! .events
//! .iter()
//! .filter(|event| event.meta.stream == "rush")
//! .count();
//! println!("rush events: {rush_events}");
//! ```
/// In-depth prose guides, rendered from the repository's `docs/` directory.
///
/// These pages give background and design context that does not belong on any
/// single type. They are documentation-only modules (no code).
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*;
pub use crate*;