Boxcars

repository·master·Indexed 40 days ago

https://github.com/nickbabcock/boxcars

A high-performance, safe, and ergonomic Rust library for parsing Rocket League replay files. It serves as a low-level parsing engine suitable for CLI tools, backend analyzers, or web applications via WebAssembly. Boxcars allows for optimized parsing by skipping network data to extract header metadata (such as goals and scores) up to 1000x faster. Version 0.11.5.

Tokens
8.1K
Snippets
33
Records
48
Agent score
99%

What's inside Boxcars

  1. Understand the Boxcars data model vs rattletrap

    master

    Boxcars provides a lower-level, more raw view of replay data compared to rattletrap. While rattletrap performs convenience conversions and produces larger JSON output, Boxcars omits these to remain lightweight and focused on parsing.

    To derive information that rattletrap provides automatically, you can use the following patterns in Boxcars:

    • To derive object_name: Access replay.objects[x.object_id]
    • To derive name: Access replay.names[x.name_id]
    • To derive attribute name: Access replay.objects[attribute.object_id]
  2. Optimize parsing by skipping network data

    master
    If you only need metadata like goals or scores, you can achieve a significant speedup (up to 1000x) by directing Boxcars to only parse the replay header and skipping the network data (the body). This is useful for aggregating thousands of replays quickly to provide immediate responses, followed by a full parse later for deeper insights.
  3. Run the Boxcars fuzzing suite

    master

    Boxcars is extensively fuzzed against malicious input. To run the fuzzing suite, you must first install cargo-fuzz. The recommended scenario to run is no-crc-body, which fuzzed all aspects of the replay without a CRC check.

    # Install cargo-fuzz
    cargo install cargo-fuzz
    
    # Run the recommended fuzzing scenario
    cargo +nightly fuzz run no-crc-body
  4. Run Boxcars benchmarks

    master

    You can run the built-in benchmarks using cargo bench. To see if compiling for your specific CPU architecture provides performance improvements, use the target-cpu=native flag.

    cargo bench
    
    # For CPU-specific optimizations:
    RUSTFLAGS="-C target-cpu=native" cargo bench
  5. Quick Start: Parse a Rocket League replay to JSON

    master

    To parse a Rocket League replay file and output its structure as JSON, use the ParserBuilder to configure the parsing requirements. By default, Boxcars ignores errors in the network data (the body) to ensure you can still access header information even after a game patch. To require both header and network data to be valid, use the .must_parse_network_data() method.

    use boxcars::{ParseError, Replay};
    use std::error;
    use std::fs;
    use std::io::{self, Read};
    
    fn parse_rl(data: &[u8]) -> Result<Replay, ParseError> {
        boxcars::ParserBuilder::new(data)
            .must_parse_network_data()
            .parse()
    }
    
    fn run(filename: &str) -> Result<(), Box<dyn error::Error>> {
        let filename = "assets/replays/good/rumble.replay";
        let buffer = fs::read(filename)?;
        let replay = parse_rl(&buffer)?;
        serde_json::to_writer(&mut io::stdout(), &replay)?;
        Ok(())
    }
  6. Identify TickMarks in replays

    master

    A TickMark represents a significant game event (like a goal) that is placed in the replay slightly before the event actually occurs to allow for ramp-up time.

    Example: A tickmark at frame 396 might represent a goal occurring at frame 441.

    pub struct TickMark {
        pub description: String,
        pub frame: i32,
    }
  7. Identify Actors, Objects, and Streams

    master

    The network data uses several distinct ID types to track entities:

    • ActorId: Identifies a specific entity (e.g., a car or ball). Note that IDs can be reused if an actor is destroyed and a new one spawns.
    • ObjectId: A unique identifier for an object in the replay hierarchy.
    • StreamId: A compressed version of an ObjectId used within the attribute stream to save space.
  8. Understand the Frame data structure

    master

    A Frame represents a single point in time in the replay. It contains:

    • time: The timestamp in seconds.
    • delta: The time elapsed since the previous frame.
    • new_actors: A list of NewActor objects that appeared this frame.
    • deleted_actors: A list of ActorIds that were destroyed.
    • updated_actors: A list of UpdatedAttribute objects representing property changes (like position or rotation) for existing actors.
  9. Configure corruption checking in ParserBuilder

    master
    Boxcars can be configured to handle replay corruption checks differently. By default, it checks for corruption when an error occurs, but you can configure the parser to either always check for corruption or never check for it.
  10. Understand the Replay data model

    master

    A Rocket League replay is decoded into a Replay struct. This struct contains the header information, network frames, keyframes, and various metadata like tick marks and debug info.

    Note on Serialization: The Replay model is designed for JSON serialization. However, deserialization from JSON is not implemented because the JSON output is lossy (e.g., distinguishing between Name and Str types or different numeric types). For lossless persistence of already-decoded network data, use the types in crate::network instead.

    // The core structure representing a decoded replay
    pub struct Replay {
        pub header_size: i32,
        pub header_crc: u32,
        pub major_version: i32,
        pub minor_version: i32,
        pub net_version: Option<i32>,
        pub game_type: String,
        pub properties: Vec<(String, HeaderProp)>,
        pub content_size: i32,
        pub content_crc: u32,
        pub network_frames: Option<NetworkFrames>,
        pub levels: Vec<String>,
        pub keyframes: Vec<KeyFrame>,
        pub debug_info: Vec<DebugInfo>,
        pub tick_marks: Vec<TickMark>,
        pub packages: Vec<String>,
        pub objects: Vec<String>,
        pub names: Vec<String>,
        pub class_indices: Vec<ClassIndex>,
        pub net_cache: Vec<ClassNetCache>,
    }
  11. Optimize parsing speed by skipping network data

    master
    If you only need metadata stored in the replay header (such as goals or scores), you can achieve up to a 1000x speedup by skipping the network data parsing. This is ideal for high-performance aggregation tasks where you need to process thousands of replays per second to provide immediate responses.