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.
Development Checkout
Clone with submodules when you want to run the repository's w3gjs parity and speed comparison scripts:
For an existing checkout:
Usage
use W3GReplay;
Lower-level parser layers are also public:
RawParserfor replay headers and compressed data blocksMetadataParserfor lobby/map/player setup dataGameDataParserandActionParserfor timeslots, chat, leave events, and player actionsReplayParserfor 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 ;
Upstream Parity
From a development checkout, check every replay fixture in upstream/w3gjs/test/replays for output parity against w3gjs:
The parity sweep reports:
- exact canonical JSON byte parity, including
parseTime - normalized canonical JSON parity with
parseTimeremoved
parseTime is expected to break exact parity because it measures each parser's runtime. Normalized parity is the useful output-equivalence signal.
Useful options:
Recent local parity 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
Intentional Divergences
w3grs is stricter than w3gjs about required replay metadata structure. For example, the metadata parser returns an error when the lobby setup marker is not the expected 0x19 byte, while w3gjs logs the unknown chunk and keeps parsing. This is intentional: the marker is an internal W3G consistency check, not a user-facing replay metric, and treating an invalid marker as an error helps catch corrupt or out-of-sync replay metadata early. Nearby length fields such as remainingBytes are likewise internal format fields.
w3grs also treats incomplete raw replay blocks and malformed top-level game-data block headers as parse errors instead of returning partial data. Inside timeslots, it keeps w3gjs's best-effort behavior for clipped action payloads.
For unknown-player gameplay records, w3grs is more tolerant than w3gjs: command blocks and chat messages for players that are not present in the lobby metadata are ignored rather than logged or allowed to throw. This keeps library parsing quiet and fallible through Result instead of process output or panics.
The low-level Rust API also returns parsed game_data_blocks directly instead of exposing them only through Node-style events. This keeps the same underlying replay data but presents it in a Rust-friendly result structure.
Benchmark
From a development checkout with the submodule initialized, compare local w3gjs and w3grs parsing speed on the same replay:
Useful options:
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.
Use --phases to include a Rust parser phase breakdown for raw block parsing, decompression, metadata, setup, game data scanning, postprocessing, and final output construction. Phase output also includes game-data counters for scanned blocks, command blocks, actions, summary actions, and skipped data.
For Rust-only phase timing, run the benchmark binary directly:
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.097 30.548 26.996 34.101 2
w3grs 0.800 0.400 0.382 0.418 2
w3grs mean speedup vs w3gjs: 76.34x
Benchmark results vary by machine, replay, iteration count, and current CPU load. Use larger iteration counts for less noisy comparisons:
All-Replay Speed Sweep
The parity script also times both parsers across the whole upstream replay corpus:
The speed sweep reports:
w3gjsandw3grsmean parse time per replay- aggregate mean/min/max speedup
Recent local speed result on the upstream submodule replay fixtures with 1 timed parse and no warmup:
Speedup mean/min/max: 45.31x / 11.80x / 105.16x