Crates.io Workflow Status

s2protocol-rs

A nom parser for the Starcraft 2 Protocol Replay format. Additionally transduces through the replays to provide SC2ReplayState that keeps track of units, players, buildings, movement, units initialized and died.

Generating protocol-specific code:

The rust code for the protocols versions available were generated using: This would now be compared with ./src/versions/protocol99999.template file and from there we can analyze what has changed. Notably, the number of bits used for the Chat Message is still miscalculated to 3 so it needs to be dismissed.

```bash mkdir src/versions/protocol89720/ RUSTLOGSPANEVENTS=full RUSTLOG=debug cargo watch -i src/versions/protocol89720/mod.rs -x 'run -- --source ../s2protocol/json/protocol89720.json generate --output src/versions/protocol89720/mod.rs'

Add the new module to src/versions/mod.rs

Run rust format on the new src/versions/protocol87702/mod.rs file

cargo check, cargo build, etc

Additionally some code to transform from Protocol-Specific to Protocol-Agnostic was added, TODO: Add to generator.rs

```

version compatibility.

After further testing, it seems most of the types are compatible between versions, so only when they differ would they make part of the protocol version. Since I started this exercise on protocol87702, all types would be relative to it. That is, most modules would re-use protocol87702 as much as possible. This explains why old-er versions such as 75689 would still reference 87702 as much as possible.

The generator above thus would show example code and does not reflect anymore the current S2ProtoResult created in favour of unwrapping/panic'ing.

JSON Sources

Blizzard/s2protocol repo

Motivation

The goal is to learn how to parse binary files format with nom and to learn how the Starcraft 2 Replay file is so incredibly small for the amount of information it packs.

From the available data, generative art can be created, for example by using - rerun : See the repo swarmy - lyon (PoC in progress in cooper) - yew cooper - eframe/egui: See repo eframes-c2 - bevyengine/bevy can be used to see: - An Enhanced Replay Minimap - Additional statistics.

Consuming events

To consume events, they are currently loaded in memory in a HashMap:

GameLoop -> Vec<EventTypes>

rust let include_stats = false; let mut replay = SC2ReplayState::new(file_path, SC2ReplayFilters::default(), include_stats).unwrap(); // at this point, all events frcom the MPQ file at `file_path` have been loaded to memory. // To progress through the game loop, the `replay` state machine transduces from one gameloop to the next one. // This means it recycles variables, sets position, maintains active units, etc. // For each transduce step, an SC2EventType is returned and the unit IDs that have been changed. // These "units" properties can be looked up in the `replay` state machine further. // In this example, the `add_tracker_event` and the `add_game_event` also are sent a reference to the SC2ReplayState // For a working example, see the swarmy repo referenced above. while let Some((event, updated_units)) = replay.transduce() { match event { SC2EventType::Tracker { tracker_loop, event, } => add_tracker_event(&self, tracker_loop, &event, updated_units)?, // Some code accessing the Tracker Events SC2EventType::Game { game_loop, user_id, event, } => add_game_event(&self, game_loop, user_id, &event, updated_units)?, } }

Current issues

Currently we load all events in memory, Perhaps we can try to read batches on events by keeping MPQ nom parser &[u8] reference. For example, we could read different sections, and return events in different sections in a batch of evenst through a game loop.

TODO

We can check that, if some module is exactly the same everywhere, we only create it once and re-use it everywhere. This because the compilation time is getting out of hand.

Status