w3grs 0.1.0

A Rust port of w3gjs for parsing Warcraft III replay files.
Documentation

w3grs

w3grs is a Rust port of w3gjs, intended to be a clean library for parsing Warcraft III replay files in other Rust projects.

The upstream TypeScript source is tracked as a Git submodule in upstream/w3gjs for parity tests, benchmarks, and future maintenance. The published crate contains the Rust library and a small fixture subset, not the full upstream replay corpus.

Installation

w3grs requires Rust 1.85 or newer.

cargo add w3grs

Development Checkout

Clone with submodules when you want to run the repository's w3gjs parity and speed comparison scripts:

git clone --recurse-submodules git@github.com:wakamex/w3grs.git

For an existing checkout:

git submodule update --init --recursive

Usage

use w3grs::W3GReplay;

fn main() -> w3grs::Result<()> {
    let mut parser = W3GReplay::new();
    let replay = parser.parse_file("replay.w3g")?;

    println!("{} on {}", replay.matchup, replay.map.file);
    println!("players: {}", replay.players.len());

    Ok(())
}

Lower-level parser layers are also public:

  • RawParser for replay headers and compressed data blocks
  • MetadataParser for lobby/map/player setup data
  • GameDataParser and ActionParser for timeslots, chat, leave events, and player actions
  • ReplayParser for the combined low-level parse output

Consumers that need both the high-level summary and the raw action stream can parse once and use the timed action helper:

use w3grs::{W3GReplay, action::format_fourcc_or_hex};

fn main() -> w3grs::Result<()> {
    let mut parser = W3GReplay::new();
    let parsed = parser.parse_file_detailed("replay.w3g")?;

    println!("{} on {}", parsed.summary.matchup, parsed.summary.map.file);
    for timed in parsed.low_level.timed_actions() {
        println!(
            "frame={} player={} action=0x{:02x}",
            timed.frame,
            timed.player_id,
            timed.action.id()
        );
    }

    let order = format_fourcc_or_hex(*b"trah");
    println!("formatted order id: {order}");

    Ok(())
}

Benchmark

From a development checkout with the submodule initialized, compare local w3gjs and w3grs parsing speed on the same replay:

node scripts/benchmark.mjs --prepare upstream/w3gjs/test/replays/132/reforged1.w3g

Useful options:

node scripts/benchmark.mjs replay.w3g --iterations 100 --warmup 10
node scripts/benchmark.mjs replay.w3g --json

The benchmark reads the replay once per parser process, warms both parsers, then reports timed in-process parses. --prepare runs the local w3gjs install/build and builds the Rust benchmark binary in release mode.

Example smoke result on this repo's reforged1.w3g fixture with 2 timed iterations and 1 warmup:

Replay: upstream/w3gjs/test/replays/132/reforged1.w3g
Iterations: 2 timed, 1 warmup

Parser   total ms   mean ms   min ms    max ms    players
w3gjs       61.179    30.589    30.201    30.977        2
w3grs        1.863     0.932     0.849     1.014        2

w3grs mean speedup vs w3gjs: 32.84x

Benchmark results vary by machine, replay, iteration count, and current CPU load. Use larger iteration counts for less noisy comparisons:

node scripts/benchmark.mjs upstream/w3gjs/test/replays/132/reforged1.w3g --iterations 100 --warmup 10

Upstream Parity And Speed Sweep

From a development checkout, check every replay fixture in upstream/w3gjs/test/replays for output parity while timing both parsers:

node scripts/compare-all.mjs --prepare --iterations 3 --warmup 1

The sweep reports:

  • exact canonical JSON byte parity, including parseTime
  • normalized canonical JSON parity with parseTime removed
  • w3gjs and w3grs mean parse time per replay
  • aggregate mean/min/max speedup

parseTime is expected to break exact parity because it measures each parser's runtime. Normalized parity is the useful output-equivalence signal.

Useful options:

node scripts/compare-all.mjs --iterations 10 --warmup 2
node scripts/compare-all.mjs --json
node scripts/compare-all.mjs --fail-on-mismatch --write-mismatches tmp/parity

Recent local smoke result on the upstream submodule replay fixtures with 1 timed parse and no warmup:

Replays: 50
Exact byte parity: 0/50 (mismatches include expected parseTime differences)
Normalized parity without parseTime: 50/50
Speedup mean/min/max: 17.99x / 2.81x / 78.62x